% \iffalse meta-comment
%
%% File: hyperref-generic.dtx
%
% Copyright (C) 2021-2024 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>
\DocumentMetadata{pdfstandard=A-2b}
\documentclass{l3doc}
\usepackage{tabularx,array,booktabs}
\hypersetup{pdfauthor=The LaTeX Project,
pdftitle=generic hyperref driver (LaTeX PDF management testphase bundle)}
\premulticols=4cm
\begin{document}
\DocInput{\jobname.dtx}
\end{document}
%
% \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.96o, released 2024-12-20}
%
% \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 (this requires \LaTeX-2022-06-01 or newer):
% \begin{verbatim}
% \DocumentMetadata %loads the PDF management and 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 the \pkg{l3color} module 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}.
% \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}, information 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 are added by code from \pkg{l3pdfmeta}.
% (without the pdfmanagement the XMP-metadata can be added with packages 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 \pkg{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 data 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 It is possible to store titles in more than one language. If the value begins with
% an \enquote{optional argument} which represents a language tag, the value is taken
% as a comma list and split. The first value is used for the Info dictionary,
% the others are used in the XMP-metadata. Commas in a title must then be
% protected with braces:
%
% \begin{verbatim}
% pdftitle = {[en]English Title,[de] Deutscher Titel,[fr]{titre français, avec comma}}
% \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{DocumentMetadata} should be used:
% \begin{verbatim}
% \DocumentMetadata{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'|.
%
%
% \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{Commands to create \enquote{external} references}
% \pkg{hyperref} has three commands related to external references like
% URL and file: \cs{url},
% \cs{nolinkurl} and \cs{href}. The first two take one argument,
% while the last has two: the url and some free text.
%
%
% \cs{url} and \cs{href} create link annotations. \cs{url} creates always an URI
% type, \cs{href} creates URI, GoToR and Launch
% depending on the structure of the argument.
%
% \cs{href} has to create a (in the PDF) valid url or file name from its first argument.
% \cs{url} has to create a (in the PDF) valid url from its only argument and has also to print
% this argument as url. \cs{nolinkurl} only prints the url.
%
% For the printing \cs{url} and \cs{nolinkurl} rely on the url package and its \cs{Url} command.
%
% (Expandable) commands are expanded and special chars can also be input by commands but
% beside this no conversion is done: for all input \pkg{hyperref} basically assumes that
% the input is already a valid percent encoded url or a valid file name. \pkg{hyperref} also
% doesn't extend or add protocols.
%
% As nowadays everyone is used to copy and paste links with all sorts of unicode into a browser and
% they work the \pkg{hyperref} input is clearly rather restricted.
%
% So the new driver tries to extend the input and print options. Both \cs{href} and \cs{url}
% can now be told to accept non-ascii url's and to convert them internally to
% percent encoding. It is possible to define a standard protocol and so to avoid to
% have to type it all the time.
%
% But extending the \emph{print} options for \cs{url} and \cs{nolinkurl} while still
% using the url-package is hard to impossible in pdf\LaTeX{} due to the way the url package works.
% Some chars can be added with the help of \cs{UrlSpecial} (at the cost of warnings)
% but it doesn't work for every input and documenting and explaining all the edge cases is no joy.
% So instead the new driver offers here the option to use different commands to format
% the printed output. It must be noted that this disable the special \enquote{hyphenation} method of
% url's.
%
%
% \subsection{Special problem: links to files}
%
% When a file is linked with \cs{href} than normally it is added as URI link. The exceptions are PDF's:
% for them PDF has the special type GoToR which allows also to link to a destination or a special page.
%
% After a number of tests with various PDF viewer established that non-ascii files names don't
% work at all with a simple file name specification GoToR links now use a full
% filespec dictionary. This works better, but still no every PDF viewer support this correctly.
% on various system.
%
% The following can be used to test viewers. It assumes that a \texttt{test.pdf},
% a \texttt{grüßpdf.pdf} and a \texttt{grüße.txt} are in the current folder.
%
% \hrefpdf{test.pdf}{test-ascii}
%
% \hrefpdf{grüßpdf.pdf}{test grüßpdf.pdf}
%
% \hrefurl[urlencode]{grüße.txt}{test grüße.txt}
%
%
% \subsection{Splits}
%
% \cs{href} tries to be clever and to detect from the argument
% if a url or a file link or a launch command should be created.
%
% The rules are not trivial, and they make the code complicated.
% This detection also makes it more difficult to handle special cases
% like non-ascii input for the link types.
%
% For this reason three new commands have been create:
%
% \begin{itemize}
% \item \cs{hrefurl} for standard urls (and non-pdf files)
% \item \cs{hrefpdf} for references to pdf files
% \item \cs{hrefrun} for launch links
% \end{itemize}
%
% The new commands don't use prefixes like \cs{href}.
% Their argument should be the real content.
%
% \subsection{Options}
% All \cs{href} commands and \cs{url} have an option argument for keyval syntax.
% It accepts the following keys. Not all keys make sense for all keys, but they don't
% error, they are silently ignored. The optional argument can currently not be used together
% with the \cs{urldef} command.
%
% \begin{tabular}{llp{6cm}}
% key & applicable commands & note\\\hline
% urlencode & \cs{hrefurl} & if set the code will convert the argument to percent encoding. This allows non-ascii input.\\
% protocol & \cs{hrefurl}, \cs{url} & This sets a prefix/protocol that is added to the url, see below. \\
% format & \cs{url} & a command used to format the printed text. It replaces the standard \cs{Url}. This can improve non-ascii
% typesetting at the cost of losing the special line breaking.\\
% destination & \cs{href}, \cs{hrefpdf} & A destination name in the PDF\\
% page & \cs{href}, \cs{hrefpdf} & destination page, default: 1\\
% pdfremotestartview &\cs{href}, \cs{hrefpdf} & start view, default: Fit\\
% ismap & \cs{href}, \cs{hrefurl} & see PDF reference\\
% afrelationship & \cs{href}, \cs{hrefpdf} & Changes the /AFRelationship key of the filespec dictionary. The value should be a PDF name without the starting slash.\\
% run-parameter & \cs{hreflaunch} & run parameter (see the PDF reference)\\
% nextactionraw & various & puts a /Next entry in the action dictionary (see the PDF reference)\\
% \end{tabular}
%
%
% The first four keys can be set also in \cs{hypersetup} for all following commands in
% the current group through the keys
% \texttt{href/urlencode}, \texttt{href/protocol}, \texttt{href/destination}, \texttt{href/format}.
%
% It is possible to define own url commands with specific options e.g. with
%
% \begin{verbatim}
% \NewDocumentCommand\myurl{O{}}{\url[protocol=https://,format=\textsc,#1]}
% \end{verbatim}
%
% \section{Link decorations: border, color, OCG-color, \ldots}
% Some main changes are
% \begin{itemize}
% \item The default colors have been changed.
% \item Citations have by default no special color, they are
% colored like other internal links. You can use |citecolor| and |citebordercolor| to
% assign them a special color. This color is not reset if you use |allcolors| or
% switch to another color scheme. If you want the colors to follow |linkcolor| again
% you should remove the label |hyp/cite| and/or |hyp/citeborder|
% from the hook |hyp/link/cite|.
% \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 |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
% |primary-colors| (the colors as \pkg{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}
%
% \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,
% \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 boolean are used by the |colorlinks| and |ocgcolorlinks| and related keys.
% These keys insert 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.
% \end{variable}
% \subsection{Changed behaviour}
% \begin{description}
% \item[colorlinks] |colorlinks| or |colorlinks=true| will as before disable the |pdfborder|
% (|colorlinks=false| will leave the |pdfborder| untouched), 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 completely 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 \pkg{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 |destlabel| (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 \pkg{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.
%
% \DescribeHypkey{nested-links}%
%
% Links are sometimes nested. E.g. if a section heading contains a reference
% it can lead to nested links in the table of contents or if |\nameref| is used.
% That is not forbidden and normally work as expected: If the link area overlap
% normally the inner link is \enquote{on top} and chosen at a click.
% But it is not always actually wanted, so with the |nested-links| (a boolean key)
% it is possible to disable such nested links.
%
% \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{DocumentMetadata}
% \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{DocumentMetadata}:
% \begin{verbatim}
% \DocumentMetadata{pdfstandard=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
% unpredictable how viewers which support |FitR| handles zero sizes.
%
% \item |pdfstartview| and |pdfremotestartview| will pass
% the values as absolute coordinates.
% \end{itemize}
% \end{itemize}
%
% \subsection{Names of destinations}
% hyperref creates two types of destination names: For numbered structures
% (so when the anchor is set by \cs{refstepcounter}) it builds the name
% from the counter name and the \cs{theH...} representation: |.\theH|.
%
% For unnumbered structures, e.g. starred chapters or anchors created with \cs{phantomsection}
% it uses names like |section*.| and |chapter*.|.
%
% Typically the name of destination can be retrieved by setting a label, this works also
% with unnumbered sections.
% The anchor and also the page can be retrieve in an expandable way
% with the help of commands from the
% \pkg{refcount} package which is loaded by hyperref. For example with the
% following commands it is possible to use the label to create a bookmark:
%
% \begin{verbatim}
% \bookmark[dest=\getrefbykeydefault{label}{anchor}{Doc-Start}]{my bookmark}
% \bookmark[dest=page.\getrefbykeydefault{label}{page}{Doc-Start}]{my bookmark}
% \end{verbatim}
%
% If a \cs{HyperDestNameFilter} is defined, this must be added around the definition,
% so actually the full code has to look like this
% \begin{verbatim}
% \bookmark[dest=
% \HyperDestNameFilter{\getrefbykeydefault{label}{anchor}{Doc-Start}}]{mysection}
% \end{verbatim}
% To simplify this hyperref provides |\hyperget{anchor}{label}| and
% |\hyperget{pageanchor}{label}|
%
%\section{Assorted key descriptions}\label{sec:keydesc}
%The following gives a few details to some keys that are perhaps not
%completely 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 necessarily 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<>
% /Subtype/Link/A<>
% /Subtype/Link/A<>
% \end{verbatim}
% Typically PDF viewer can handle only GoToR annotations 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}\DescribeHypkey{pdfmetadate}
% Setting these keys is normally not needed. If they are used the values
% of the first two keys are stored directly in the Info dictionary for
% |/Creationdate| and |/ModDate|. All three keys are used in XMP-metadata.
% 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{DocumentMetadata} 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 %% @@_link_goto_begin:nw : start command for links to internal destination
%^^A %% replaces \find@pdflink
%^^A %% @@_link_goto_end:
%^^A %% @@_destination:n : sets an anchor, replaces \new@pdflink
%^^A %% \@@_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 %% *\@@_property_record:nn
%^^A %% *\property_if_recorded:nn
%^^A %% *\property_ref_undefined_warn:nn,
%^^A %% % helps to display key list messages
%^^A %% \@@_clist_display:n
%^^A %%
%^^A %% \@@_info_generate_addons: what did this do??
%^^A %%
%^^A %% \g_@@_AcroForm_CoFields_prop
%^^A %% \g_@@_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 %% \g_@@_bordercolormodel_tl
%
%^^A %% \l_@@_dest_pdfview_tl
%^^A %% list of commands which probably will have to change
%^^A TODO: move hrefurl, hrefrun, hrefpdf into hyperref. They should also work
% \end{documentation}
% \begin{implementation}
% \part{\pkg{hyperref-generic} driver implementation}
% \begin{macrocode}
%<*package>
%<@@=hyp>
% \end{macrocode}
% \begin{macrocode}
\ProvidesFile{hgeneric-testphase.def}[2024-12-20 v0.96o %
generic Hyperref driver for the LaTeX PDF management testphase bundle]
\RequirePackage{etoolbox} %why?
% \end{macrocode}
% Temporary command definition, can be remove when hyperref is update too.
% \begin{macrocode}
\long\def\Hy@ReturnAfterFi#1\fi{\fi#1}
% \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}
\cs_if_exist:NTF \DocumentMetadata
{
\msg_new:nnnn
{ hyp }
{ missing-resource-management }
{ The~PDF~resource~management~is~required~for~this~hyperref~driver! }
{
Activate~it~with \\
\tl_to_str:n{\DocumentMetadata{}}\\
before~\tl_to_str:n{\documentclass}
}
}
{
\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{\DocumentMetadata{}}\\
before~\tl_to_str:n{\documentclass}
}
}
% \end{macrocode}
% The pdfversion should be set in \cs{DocumentMetadata}
% \begin{macrocode}
\msg_new:nnnn
{ hyp }
{ pdfversion-disabled }
{
This~hyperref~driver~ignores~the~pdfversion~key!\\
Set~the~pdfversion~in~\token_to_str:N \DocumentMetadata
}
{
For example:\\
\tl_to_str:n
{
\DocumentMetadata { 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}
% A message for creator and producer which can't be removed.
% \begin{macrocode}
\msg_new:nnn
{ hyp }
{ empty-info-value }
{
Empty~value~for~key~#1.\\
This~isn't~honored~by~all~backends.
}
% \end{macrocode}
% \section{Variants}
% \begin{macrocode}
\cs_generate_variant:Nn\pdf_destination:nn {nf}
\cs_generate_variant:Nn\pdf_object_ref:n {e}
\cs_generate_variant:Nn\pdf_pageobject_ref:n {e}
% \end{macrocode}
% \section{Overwriting/providing commands from hyperref}
% \pkg{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{function}{\hypercalcbp}
% We define a better (expandable) version of \cs{hypercalcbp}
% \end{function}
% \begin{macro}[EXP]{\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}
%
% The pdfversion should be set in \cs{DocumentMetadata} 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:nne {hyp}{unknown-key-to-Hyp}{#1} }
\cs_set_protected:Npn \hypersetup #1
{
%\kvsetkeys{Hyp} {#1}
\keys_set:nn { hyp }{ #1 }
}
% TODO for now unknown keys should only give warnings.
\keys_define:nn { hyp }
{
unknown .code:n =
{
\msg_warning:nneee { hyp } { unknown-key }
{ hyp }{ \l_keys_key_str } { #1 }
}
}
% \end{macrocode}
%
% Hyperref creates a number of destinations automatically. E.g. in unnumbered
% chapters and sections and with \cs{phantomsection}. The following key allows
% to force a specific name for the destination so that it can be used by bookmarks.
% \begin{macrocode}
\keys_define:nn { hyp }
{
next-anchor .code:n =
{
\AddToHookNext{__hyp/dest/make}
{\Hy@MakeCurrentHref{#1}}
}
}
% \end{macrocode}
%
% Allow non-ascii in href, and add more href versions.
% We add a few new keys:
% |urlencode| to force percent encoding (\cs{hrefurl}, \cs{href})
% |protocol | to add a protocol (\cs{hrefurl},
% \cs{href} doesn't work here as it needs the colon for the split and the guessing.)
% |destination| to add a destination (\cs{hrefpdf})
%
% \begin{macrocode}
\bool_new:N \l_@@_href_url_encode_bool
\bool_new:N \l_@@_href_url_ismap_bool
\tl_new:N \l_@@_href_url_protocol_tl
\tl_new:N \l_@@_href_pdf_destination_tl
\tl_new:N \l_@@_href_pdf_page_tl
\tl_new:N \l_@@_href_run_parameter_tl
\cs_new_protected:Npn \@@_href_url_format: {\begingroup\Url}
\keys_define:nn { hyp / href }
{
,urlencode .bool_set:N = \l_@@_href_url_encode_bool
,format .code:n = { \cs_set:Nn \@@_href_url_format: {#1} },
,protocol .tl_set:N = \l_@@_href_url_protocol_tl
,destination .tl_set:N = \l_@@_href_pdf_destination_tl
,pdfremotestartview .code:n =
{
\keys_set:nn { hyp }
{ pdfremotestartview = #1 }
}
,page .code:n =
{
\tl_set:Nn \l_@@_href_pdf_page_tl {#1}
\tl_set:Nn \Hy@href@page {#1}
}
,ismap .bool_set:N = \l_@@_href_url_ismap_bool
,run-parameter .tl_set:N = \l_@@_href_run_parameter_tl
,nextactionraw .code:n =
{ %perhaps some safety match later, see hyperref code
\tl_if_empty:nTF {#1}
{
\pdfdict_remove:nn{l_hyp/annot/A}{Next}
}
{
\pdfdict_put:nnn{l_hyp/annot/A}{Next}{#1}
\tl_set:Nn \Hy@href@nextactionraw {/Next~#1}
\keys_set:nn {hyp }{ pdfnewwindow = true}
}
}
,afrelationship .code:n =
{
\pdfdict_put:nne
{ l_pdffile/Filespec}{AFRelationship}{ \pdf_name_from_unicode_e:n {#1}}
}
}
\keys_define:nn { hyp }
{
,href / urlencode .bool_set:N = \l_@@_href_url_encode_bool
,href / urlencode .default:n = {true}
,href / urlencode .initial:n = {false}
,href / protocol .tl_set:N = \l_@@_href_url_protocol_tl
,href / destination .tl_set:N = \l_@@_href_pdf_destination_tl
,href / format .code:n = { \cs_set:Nn \@@_href_url_format:{#1} }
}
\hook_new_pair:nn{cmd/href/before}{cmd/href/after}
\DeclareRobustCommand*{\href}[1][]{%
\mode_leave_vertical:
\hook_use:n{cmd/href/before}
\group_begin:
\keys_set:nn { hyp / href } {#1}
\bool_if:NTF \l_@@_href_url_encode_bool
{
\tl_set:Nn \l_@@_text_enc_uri_print_tl {utf8/URI}
}
{
\tl_set:Nn \l_@@_text_enc_uri_print_tl {utf8/string}
}
\@ifnextchar\bgroup\Hy@href{\hyper@normalise\href@}%
}
\begingroup
\catcode`\$=6 %
\catcode`\#=12 %
\gdef\href@$1{\expandafter\href@split$1##\\}%
\gdef\href@split$1#$2#$3\\$4{%
\hyper@@@@link{$1}{$2}{$4}%<---@@-docstrip doubling!
\endgroup
\hook_use:n{cmd/href/after}
}%
\endgroup
\hook_new_pair:nn{cmd/hrefurl/before}{cmd/hrefurl/after}
\DeclareRobustCommand*{\hrefurl}[1][]
{
\mode_leave_vertical:
\hook_use:n{cmd/href/before}
\group_begin:
\keys_set:nn { hyp / href } {#1}
\bool_if:NTF \l_@@_href_url_encode_bool
{
\tl_set:Nn \l_@@_text_enc_uri_print_tl {utf8/URI}
}
{
\tl_set:Nn \l_@@_text_enc_uri_print_tl {utf8/string}
}
\hyper@normalise\@@_href_url_aux:nn}
\cs_new_protected:Npn \@@_href_url_aux:nn #1 #2
{
\exp_args:Nno\hyper@linkurl{#2}{\l_@@_href_url_protocol_tl#1}
\group_end:
\hook_use:n{cmd/href/after}
}
\hook_new_pair:nn{cmd/hrefpdf/before}{cmd/hrefpdf/after}
\DeclareRobustCommand*{\hrefpdf}[1][]
{
\mode_leave_vertical:
\hook_use:n{cmd/hrefpdf/before}
\group_begin:
\keys_set:nn { hyp / href } {#1}
\hyper@normalise\@@_href_pdf_aux:nn
}
\cs_new_protected:Npn \@@_href_pdf_aux:nn #1 #2
{
\exp_args:Nnno\hyper@linkfile{#2}{#1}{\l_@@_href_pdf_destination_tl}
\group_end:
\hook_use:n{cmd/hrefpdf/after}
}
\hook_new_pair:nn{cmd/hrefrun/before}{cmd/hrefrun/after}
\DeclareRobustCommand*{\hrefrun}[1][]
{
\mode_leave_vertical:
\hook_use:n{cmd/hrefrun/before}
\group_begin:
\keys_set:nn { hyp / href } {#1}
\hyper@normalise\@@_href_run_aux:nn
}
\cs_new_protected:Npn \@@_href_run_aux:nn #1 #2
{
\exp_args:Nnno\hyper@linklaunch{#1}{#2}{\l_@@_href_run_parameter_tl}
\group_end:
\hook_use:n{cmd/hrefrun/after}
}
\hook_new_pair:nn{cmd/url/before}{cmd/url/after}
\DeclareRobustCommand*{\url}[1][]
{
\mode_leave_vertical:
\hook_use:n{cmd/url/before}
\group_begin:
\keys_set:nn {hyp / href } {#1}
\bool_if:NTF \l_@@_href_url_encode_bool
{
\tl_set:Nn \l_@@_text_enc_uri_print_tl {utf8/URI}
}
{
\tl_set:Nn \l_@@_text_enc_uri_print_tl {utf8/string}
}
\hyper@normalise\@@_href_url_aux:n
}
\cs_new_protected:Npn \@@_href_url_aux:n #1
{
\exp_args:Nno
\hyper@linkurl{\@@_href_url_format: {#1}}
{\l_@@_href_url_protocol_tl#1}
\group_end:
\hook_use:n{cmd/url/after}
}
% \end{macrocode}
% the \cs{urldef} command doesn't like the optional argument, so we overwrite
% locally the \cs{url} command here:
% \begin{macrocode}
\def\urldef#1#2{\begingroup\def\url{\hyper@normalise\url@}\setbox\z@\hbox\bgroup
\def\Url@HyperHook##1\endgroup{\Url@def{#1}{#2}}%
% Because hyperref breaks \urldef and does not define its own (Grrrr!)...
\def\url@##1{\egroup\endgroup\DeclareRobustCommand#1{#2{##1}}}%
#2}
% \end{macrocode}
% make the new commands compatible with \cs{pdfstringdef}:
% \begin{macrocode}
\NewExpandableDocumentCommand\@@_secondoftwowithopt:wnn {omm}{#3}
\pdfstringdefDisableCommands{\let\hrefurl\@@_secondoftwowithopt:wnn}
\pdfstringdefDisableCommands{\let\hrefpdf\@@_secondoftwowithopt:wnn}
\pdfstringdefDisableCommands{\let\hrefrun\@@_secondoftwowithopt:wnn}
% \end{macrocode}
% \section{Compatibility 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 {en,ne,ee,no,eo}
% \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 }
{
,citecolor .code:n = {\@@_color_set:ne {hyp/color/cite}{#1}\@@_citecolor_hook_init:}
,citebordercolor
.code:n = {\@@_color_set:ne {hyp/color/citeborder}{#1}\@@_citebordercolor_hook_init:}
}
\cs_new_protected:Npn \@@_citecolor_hook_init:
{
\hook_gput_code:nnn { hyp/link/cite }{hyp/cite}
{
\keys_set:nn { hyp }
{
linkcolor = hyp/color/cite
}
}
\cs_gset_eq:NN \@@_citecolor_hook_init: \prg_do_nothing:
}
\cs_new_protected:Npn \@@_citebordercolor_hook_init:
{
\hook_gput_code:nnn { hyp/link/cite }{hyp/citeborder}
{
\keys_set:nn { hyp }
{
linkbordercolor = hyp/color/citeborder
}
}
\cs_gset_eq:NN \@@_citebordercolor_hook_init: \prg_do_nothing:
}
% \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 bookmarks are suppressed.
% TODO We overwrite the color key here for now, but this should be moved to bookmark
%
% \begin{macrocode}
\AddToHook { package/bookmark/after}
{
\define@key{BKM}{color}
{
\tl_if_blank:nTF {#1}
{ \cs_set_eq:NN\BKM@color\@empty }
{
\__hyp_color_set:ne {__hyp/tmpa}{#1}
\color_export:nVN
{__hyp/tmpa}
\g__hyp_bordercolormodel_str
\BKM@color
}
}
}
\legacy_if:nTF { Hy@bookmarks }
{
\AddToHook{begindocument/before}[hyperref/bookmark]
{
\RequirePackage{bookmark}
}
}
% \end{macrocode}
% empty hook chunk to ensure that the chunk exists.
% \begin{macrocode}
{
\AddToHook{begindocument/before}[hyperref/bookmark]{}
}
\legacy_if:nT {Hy@draft}
{
\PassOptionsToPackage{draft}{bookmark}
}
% \end{macrocode}
%
% \section{Reference and label commands}
% This uses the in-built property module.
%
% \begin{macro}
% {
% \@@_property_record:nn,
% }
% \begin{macrocode}
%
% \end{macrocode}
% A label command which adds the space commands from LaTeX:
% \begin{macrocode}
\cs_new_protected:Npn \@@_property_record:nn #1 #2 %label/attributes
{
\@bsphack
\property_record:nn{#1}{#2}
\@esphack
}
% \end{macrocode}
% we generate a few variants. We use ee-variants as they already exist
% in the module and once this is there it can go here.
% \begin{macrocode}
\cs_generate_variant:Nn \@@_property_record:nn {ee}
% \end{macrocode}
% \end{macro}
% \section{Variables}
% \subsection{Private temporary variables}
% At first a few generic tmp variables
% \begin{variable}
% {
% \l_@@_tmpa_tl,
% \l_@@_tmpb_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
\tl_new:N \l_@@_tmpb_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}
%
% It is also unclear how the /Contents entry would look at best.
% So we use sockets. The first argument is the target (url or destination),
% For GoTo we also pass the text as argument.
% The sockets should put something into the relevant annotation dictionaries.
% \changes{v0.96o}{2024-10-27}{moved dictionary command into socket so that
% it can be fully replaced.}
% \begin{macrocode}
\tl_new:N\l_@@_link_Contents_tl
\socket_new:nn {hyp/link/GoTo/Contents}{2}
\socket_new:nn {hyp/link/URI/Contents}{1}
\socket_new_plug:nnn {hyp/link/GoTo/Contents}{default}
{
\@@_text_pdfstring:eoN
{ Go~to~destination~#1 }
{ \l_@@_text_enc_info_print_tl }
\l_@@_link_Contents_tl
\pdfannot_dict_put:nne {link/GoTo}{Contents}
{\l_@@_link_Contents_tl}
}
\socket_new_plug:nnn {hyp/link/URI/Contents}{default}
{
\@@_text_pdfstring:eoN
{ #1 }
{ \l_@@_text_enc_info_print_tl }
\l_@@_link_Contents_tl
\pdfannot_dict_put:nne {link/URI}{Contents}
{\l_@@_link_Contents_tl}
}
\socket_assign_plug:nn{hyp/link/GoTo/Contents}{default}
\socket_assign_plug:nn{hyp/link/URI/Contents}{default}
% \end{macrocode}
% \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}[no-user-doc]{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:Ne #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{} (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 {enN,onN,eoN,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:enN {#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
}
\cs_generate_variant:Nn \@@_text_pdfstring_info:nN {eN,oN}
% \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<>}|
% \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 <>]>>|
% (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}[no-user-doc]
% {
% \@@_PageLabels_gpush:,
% \Hy@PutCatalog,
% \HyPL@StorePageLabel
% }
% \begin{macrocode}
\cs_new_protected:Npn\@@_PageLabels_gpush:
{
\pdfmanagement_add:nne {Catalog} {PageLabels}{<>}
}
\def\Hy@PutCatalog #1 {}
\legacy_if:nT { Hy@pdfpagelabels }
{
\cs_set_protected:Npn \HyPL@StorePageLabel #1
{
\tl_gput_right:Ne \HyPL@Labels { \the\Hy@abspage<<#1>> }
\@@_PageLabels_gpush:
}
}
% \end{macrocode}
% \end{macro}
% \section{Core Hyperref Commands}
% Every \pkg{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{Link level}
% Links can be nested. Inner links need perhaps special handling, e.g.
% to deactivate the link, or to change the border, or in the case of
% tagging to add some additional structure to handle the parent-child rules.
% We therefore add a global counter which is increased at the begin of
% link and decreased at the end.
% \begin{macro}{g_@@_linknestlevel_int}
% \begin{macrocode}
\int_new:N \g_@@_linknestlevel_int
% \end{macrocode}
% \end{macro}
%
% \begin{macrocode}
\prg_new_conditional:Npnn \@@_if_outer_link: {TF}
{
\int_compare:nNnTF { \g_@@_linknestlevel_int } > {1}
{ \prg_return_false: }
{ \prg_return_true: }
}
% \end{macrocode}
% \begin{macrocode}
\cs_new:Npn \@@_check_link_nesting:TF #1 #2
{
\use_i:nn {#1}{#2}
}
% \end{macrocode}
%
% \begin{macrocode}
\keys_define:nn { hyp }
{
nested-links .choice:,
nested-links / true .code:n =
{ \cs_set_eq:NN \@@_check_link_nesting:TF \use_i:nn },
nested-links / false .code:n =
{ \cs_set_eq:NN \@@_check_link_nesting:TF \@@_if_outer_link:TF },
nested-links .default:n = {true}
}
% \end{macrocode}
% \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:eoN
{ \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.
% We add a hook. This allows e.g. the tagging code
% to create also a structured destination.
% We don't use the cmd hook, as we want the same hook for both start commands.
% We make the current dest name available so that the hook code can use it.
% \begin{macro}[no-user-doc]
% {
% \hyper@anchor,
% \hyper@anchorstart,
% \hyper@anchorend,
% hyp/anchor,
% \l_hyp_current_dest_name_tl
% }
% \begin{macrocode}
\tl_new:N\l_hyp_current_dest_name_tl
\hook_new:n{hyp/anchor}
\cs_new_protected:Npn \hyper@anchor #1
{
\exp_args:NnV
\@@_destination:nn {#1} \l_@@_dest_pdfview_tl
\tl_set:Nn \l_hyp_current_dest_name_tl {#1}
\hook_use:n{hyp/anchor}
}
\cs_new_protected:Npn \hyper@anchorstart #1
{
\Hy@activeanchortrue
\exp_args:NnV
\@@_destination:nn {#1} \l_@@_dest_pdfview_tl
\tl_set:Nn \l_hyp_current_dest_name_tl {#1}
\hook_use:n{hyp/anchor}
}
\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:nne
{ hyp }
{ empty-destination-name }
{ \c_@@_dest_undefined_tl }
\tl_set_eq:NN \l_@@_dest_name_tmpa_tl \c_@@_dest_undefined_tl
}
{
\@@_text_pdfstring:eoN
{ \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 \pkg{hyperref} commands.
% The split 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. We store again the destination name in the
% public tl |\l_hyp_current_dest_name_tl| so that the hook code can make use of
% it
% \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
{
\int_gincr:N\g_@@_linknestlevel_int
\@@_check_link_nesting:TF
{
\Hy@VerboseLinkStart{#1}{#2}
\group_begin:
\tl_set:Nn \l_hyp_current_dest_name_tl {#2}
% \end{macrocode}
% this socket adds something to the /Contents key.
% \begin{macrocode}
\socket_use:nnn{hyp/link/GoTo/Contents}{#2}{#3}
\hook_use:n {hyp/link/#1}
\@@_link_goto_begin:nw {#2}#3\Hy@xspace@end
\@@_link_goto_end:
\group_end:
\Hy@VerboseLinkStop
}
{
\group_begin: #3\group_end:
}
\int_gdecr:N\g_@@_linknestlevel_int
}
{{\let\protect\relax#3}}
}
\cs_new_protected:Npn \hyper@linkstart #1 #2 %#1 context, #2=destination name
{
\bool_if:NT \l_@@_annot_GoTo_bool
{
\int_gincr:N\g_@@_linknestlevel_int
\@@_check_link_nesting:TF
{
\Hy@VerboseLinkStart{#1}{#2}% only for debug
\group_begin:
\tl_set:Nn \l_hyp_current_dest_name_tl {#2}
\socket_use:nnn{hyp/link/GoTo/Contents}{#2}{}
\hook_use:n {hyp/link/#1}
\@@_link_goto_begin:nw {#2}
}
{
\group_begin:
}
}
}
\cs_new_protected:Npn \hyper@linkend
{
\bool_if:NT \l_@@_annot_GoTo_bool
{
\@@_check_link_nesting:TF
{
\@@_link_goto_end:
\group_end:
\Hy@VerboseLinkStop
}
{
\group_end:
}
\int_gdecr:N\g_@@_linknestlevel_int
}
}
% \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
{
\int_gincr:N\g_@@_linknestlevel_int
\@@_check_link_nesting:TF
{
\group_begin:
\@@_text_pdfstring:eoN
{ #2}
{ \l_@@_text_enc_uri_print_tl }
\l_@@_uri_tmpa_tl
\pdfdict_put:nno{l_hyp/annot/A/URI}{URI}{\l_@@_uri_tmpa_tl}
\bool_if:NT \l_@@_href_url_ismap_bool
{
\pdfdict_put:nnn{l_hyp/annot/A/URI}{IsMap}{true}
}
% \end{macrocode}
% This socket adds something to the /Contents key.
% \begin{macrocode}
\socket_use:nn{hyp/link/URI/Contents}{#2}
\cs_set_eq:NN \# \c_hash_str
\cs_set_eq:NN \% \c_percent_str
\Hy@safe@activestrue
\mode_leave_vertical:
\pdfannot_dict_put:nne {link/URI}{A}{<<\pdfdict_use:n {l_hyp/annot/A/URI}>>}
\pdfannot_link:nen { URI }
{
}
{
\let\protect\relax
#1
\Hy@xspace@end
\Hy@VerboseLinkStop %where is the start??
}
\group_end:
}
{
\group_begin: #1 \group_end:
}
\int_gdecr:N\g_@@_linknestlevel_int
}
{{\let\protect\relax#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_generate_variant:Nn \pdffile_embed_file:nnn {noe}
\cs_new_protected:Npn \hyper@linkfile #1 #2 #3 % link text, filename, destname
{
\bool_if:NTF \l_@@_annot_GoToR_bool
{
\int_gincr:N\g_@@_linknestlevel_int
\@@_check_link_nesting:TF
{
\group_begin:
\tl_set:Ne \l_@@_filename_tmpa_tl { \text_expand:n { #2 } }
\exp_args:Ne
\pdf_object_if_exist:nF { @@_file_\tl_to_str:N \l_@@_filename_tmpa_tl }
{
\pdfdict_put:nne { l_pdffile/Filespec}{Subtype}{\pdf_name_from_unicode_e:n {application/pdf}}
\pdffile_embed_file:noe
{}
{\l_@@_filename_tmpa_tl }
{@@_file_\tl_to_str:N \l_@@_filename_tmpa_tl }
}
\pdfdict_put:nne
{l_hyp/annot/A/GoToR}
{F}
{\pdf_object_ref:e {@@_file_\tl_to_str:N \l_@@_filename_tmpa_tl}}
\@@_text_pdfstring:nnN
{ #3 }
{ \l_@@_text_enc_dest_print_tl }
\l_@@_dest_name_tmpa_tl
\tl_if_blank:eTF {#3}
{
\pdfdict_put:nne {l_hyp/annot/A/GoToR}{D}
{
[
\int_eval:n
{ \int_max:nn {0}{ 0\l_@@_href_pdf_page_tl - 1 }}
/\l_@@_dest_pdfremotestartview_tl
]
}
}
{
\pdfdict_put:nno {l_hyp/annot/A/GoToR}{D}{\l_@@_dest_name_tmpa_tl}
}
\mode_leave_vertical:
% \end{macrocode}
% We use an extra object here, as ghostscript doesn't like the
% object reference in the dict
% \url{https://chat.stackexchange.com/transcript/message/57361080#57361080}
% \begin{macrocode}
\pdf_object_unnamed_write:ne{dict}{\pdfdict_use:n {l_hyp/annot/A/GoToR}}
\pdfannot_dict_put:nne {link/GoToR}{A}{\pdf_object_ref_last:}
\pdfannot_link:nnn %expansion??
{ GoToR }
{
}
{
\let\protect\relax
#1\Hy@xspace@end
\Hy@VerboseLinkStop %where is the start??
}
\group_end:
}
{
\group_begin: #1 \group_end:
}
\int_gdecr:N\g_@@_linknestlevel_int
}
{{\let\protect\relax#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
{
\int_gincr:N\g_@@_linknestlevel_int
\@@_check_link_nesting:TF
{
\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:nne
{l_hyp/annot/A/Launch}
{Win}
{<
>}
}
\mode_leave_vertical:
\pdfannot_dict_put:nne {link/Launch}{A}{<<\pdfdict_use:n {l_hyp/annot/A/Launch}>>}
\pdfannot_link:nen
{ Launch }
{
% /A
% <<
% \pdfdict_use:n {l_hyp/annot/A/Launch}
% >>
}
{
\let\protect\relax
#2\Hy@xspace@end
\Hy@VerboseLinkStop %where is the start??
}
\group_end:
}
{ \group_begin: #2 \group_end: }
\int_gdecr:N\g_@@_linknestlevel_int
}
{{\let\protect\relax#2}}
}
% \end{macrocode}
% The actually command used by \pkg{hyperref} is \cs{@hyper@launch} which uses a delimited
% argument, because of the color the definition is a bit convoluted.
% \begin{macrocode}
\use:e
{ % 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
{
\int_gincr:N\g_@@_linknestlevel_int
\@@_check_link_nesting:TF
{
\group_begin:
\pdfmeta_standard_verify:nnTF {named_actions}{#1}
{
\mode_leave_vertical:
\pdfdict_put:nne {l_hyp/annot/A/Named}{N}
{\pdf_name_from_unicode_e:n{#1}}
\pdfannot_dict_put:nne {link/Named}{A}{<<\pdfdict_use:n {l_hyp/annot/A/Named}>>}
\pdfannot_link:nnn { 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:
}
{ \group_begin: #2 \group_end: }
\int_gdecr:N\g_@@_linknestlevel_int
}
{{\let\protect\relax#2}}
}
% \end{macrocode}
%
% \section{Link decorations}
% \subsection{Functions to export and select colors}
% We support two input syntax: color expressions and model with values.
% Exporting can be done by first setting the color with \cs{@@_color_set:nn}
% (if needed to a temporary color name)
% and then using \cs{color_export:nnN}. But we need a variant as the export
% format |space-sep-cmyk| or |space-sep-rgb| is stored in a tl.
% \begin{macrocode}
\cs_generate_variant:Nn \color_export:nnN {nVN}
% \end{macrocode}
%
% \begin{function}{\@@_color_select:n}
% \begin{syntax}
% \cs{@@_color_select:n} \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,\@@_color_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}[ %]
{
\@@_color_select_aux:wn #1
}
{
\color_select:n {#1}
}
}
\cs_new_protected:Npn \@@_color_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,\@@_color_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}[ %]
{
\@@_color_set_aux:nwn { #1 } #2
}
{
\color_set:nn {#1} {#2}
}
}
\cs_new_protected:Npn \@@_color_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 \pkg{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 }
{
,colorlinks .choice:
,colorlinks / true .meta:n =
{
,pdfborder={0~0~0}
,pdfborderstyle=
,colorurl =#1
,colorlink =#1
,colorrun =#1
,colormenu =#1
,colorfile =#1
}
,colorlinks / false .meta:n =
{
,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}{allcolors}
% \begin{macrocode}
\seq_map_inline:Nn \c_@@_annot_types_seq
{
\keys_define:nn { hyp }
{
,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 }
{
,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 }
{
,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 }
{
#1bordercolor .code:n =
{
\tl_if_empty:nTF { ##1 }
{
\pdfannot_dict_remove:nn
{link/#2}
{ C }
}
{
\@@_color_set:ne {hyp/color/#1border}{##1}
\color_export:nVN
{hyp/color/#1border}
\g_@@_bordercolormodel_str
\l_@@_tmpa_tl
\pdfannot_dict_put:nne
{link/#2}
{ C }
{ [\l_@@_tmpa_tl] }
}
}
}
}
\keys_define:nn { hyp }
{
,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 }
{
#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 }
{
,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 }
{
#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 }
{
,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:n { @@/OCG/View }
\pdf_object_new:n { @@/OCG/Print }
\pdf_object_new:n { @@/OCG/config }
\pdf_object_new:n { @@/OCG/refarray }
\pdf_object_write:nne { @@/OCG/refarray } { array }
{
\pdf_object_ref:n { @@/OCG/View }
\c_space_tl
\pdf_object_ref:n { @@/OCG/Print }
}
\pdf_object_write:nnn { @@/OCG/View } { dict }
{
/Type/OCG
/Name(View)
/Usage
<<
/Print <>~
/View <>~
>>
}
\pdf_object_write:nnn { @@/OCG/Print } { dict }
{
/Type/OCG
/Name(Print)
/Usage
<<
/Print <>~
/View <>~
>>
}
\pdfmanagement_add:nne { Catalog / OCProperties }{OCGs }{ \pdf_object_ref:n {@@/OCG/View} }
\pdfmanagement_add:nne { Catalog / OCProperties }{OCGs }{ \pdf_object_ref:n {@@/OCG/Print} }
\pdf_object_write:nne { @@/OCG/config } { dict }
{
/OFF[\pdf_object_ref:n { @@/OCG/Print }]
/AS[
<<
/Event/View
/OCGs\c_space_tl \pdf_object_ref:n { @@/OCG/refarray }
/Category[/View]
>>
<<
/Event/Print
/OCGs\c_space_tl \pdf_object_ref:n { @@/OCG/refarray }
/Category[/Print]
>>
<<
/Event/Export
/OCGs\c_space_tl \pdf_object_ref:n { @@/OCG/refarray }
/Category[/Print]
>>
]
}
\pdfmanagement_add:nne { Catalog / OCProperties }{ D }{ \pdf_object_ref:n { @@/OCG/config} }
\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}{@@/OCG/Print}
\hbox_overlap_right:n { \box_use:N \l_@@_tmpa_box }
\pdf_emc:
\pdf_bdcobject:nn {OC}{@@/OCG/View}
\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}
\bool_lazy_or:nnTF
{ \pdf_version_compare_p:Nn > {1.4} }
{ \str_if_eq_p:ee{\pdf_version_major:}{-1} }
{
\keys_define:nn { hyp }
{
,_ocgcolorlinks .meta:n =
{
ocgcolorlink=#1,
ocgcolorurl=#1,
ocgcolorfile=#1,
ocgcolorrun=#1,
ocgcolormenu=#1
}
,_ocgcolorlinks .default:n = true
}
}
{
\keys_define:nn { hyp }
{
,_ocgcolorlinks .code:n =
{
\msg_warning:nnee
{ hyp }
{ ignore-deprecated-or-unknown-option-in-pdf-version }
{ ocgcolorlinks } { \pdf_version_major:.\pdf_version_minor: }
}
}
}
\keys_define:nn { hyp }
{
,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
{
\bool_lazy_or:nnTF
{ \pdf_version_compare_p:Nn > {1.4} }
{ \str_if_eq_p:ee{\pdf_version_major:}{-1} }
{
\keys_define:nn { hyp }
{
,ocgcolor#1 .bool_set:c = { l_hyp_annot_ocgcolor#1_bool }
}
}
{
\keys_define:nn { hyp }
{
,ocgcolor#1 .code:n=
{
\msg_warning:nnee
{ hyp }
{ ignore-deprecated-or-unknown-option-in-pdf-version }
{ ocgcolor#1 }
{ \pdf_version_major:.\pdf_version_minor: }
}
}
}
}
% \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 }
{
,#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:nneee { hyp } { unknown-choice+empty }
{ #1highlight }
{ /I~(inverse), /N~(no effect), /O~(outline), /P~(inset) }
{ \exp_not:n {##1} }
}
}
}
\keys_define:nn { hyp }
{
,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:nneee { 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 }
{
hidelinks .meta:n =
{
,colorlinks = false
,ocgcolorlinks = false
,pdfborder = { 0~0~0 }
,pdfborderstyle=
}
}
\seq_map_inline:Nn \c_@@_annot_types_seq
{
\keys_define:nn { hyp }
{
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 }
{
colorscheme .code:n =
{
\prop_map_inline:cn { c_@@_colorscheme_#1_prop }
{
\keys_set:nn { hyp }
{
##1 = ##2
}
}
}
}
\keys_set:nn { hyp } {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 }
{
,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 }
{
,verbose .legacy_if_set:n = {Hy@verbose}
,debug .legacy_if_set:n = {Hy@verbose}
}
\keys_define:nn { hyp }
{
,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 }
{
,extension .tl_set:N = \XR@ext
,extension .initial:n= pdf
,hypertexnames .legacy_if_set:n = {Hy@hypertexnames}
,linkfileprefix .tl_set:N = \Hy@linkfileprefix
,localanchorname .legacy_if_set:n = {Hy@localanchorname}
,naturalnames .legacy_if_set:n = {Hy@naturalnames}
,pageanchor .legacy_if_set:n = {Hy@pageanchor}
,plainpages .legacy_if_set:n = {Hy@plainpages}
}
\keys_define:nn { hyp }
{
,linktoc .choices:nn = { none, section, all, page }
{
\cs_set_eq:Nc \Hy@linktoc { Hy@linktoc@#1 }
}
,linktoc / unknown .code:n =
{
\msg_warning:nneee { 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 }
{
,#1 .bool_set:c = {l_@@_annot_#2_bool}
}
}
% \end{macrocode}
% \end{hypkey}
%
% \begin{macrocode}
\keys_define:nn { hyp }
{
,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:nne {Catalog} { URI }{ <> }
}
\@@_store_metadata:nn {baseurl}{#1}
}
%only false does something ...
,bookmarks .choice:
,bookmarks / false .code:n = {\RemoveFromHook {begindocument/before}[hyperref/bookmark]}
,bookmarks / true .code:n = {}
,bookmarks .default:n = {true}
,bookmarksnumbered .legacy_if_set:n = {Hy@bookmarksnumbered}
,bookmarksopen .legacy_if_set:n = {Hy@bookmarksopen}
,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:nnee { 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:nneee { 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:nnee
{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:nneee { 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:nnee { 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:nnee { 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:nne {Catalog / ViewerPreferences }
{ NonFullScreenPageMode} {/#1}
}
,pdfnonfullscreenpagemode / UseAttachments .code:n =
{
\pdf_version_compare:NnTF < {1.6}
{
%message
}
{
\pdfmanagement_add:nne {Catalog / ViewerPreferences }
{NonFullScreenPageMode}{/UseAttachments}
}
}
,pdfnonfullscreenpagemode / .code:n =
{
\pdfmanagement_remove:nn {Catalog / ViewerPreferences } { NonFullScreenPageMode }
}
,pdfnonfullscreenpagemode / unknown .code:n =
{
\msg_warning:nneee { 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:nne {Catalog / ViewerPreferences }
{NumCopies}{#1}
}
}
{
\msg_warning:nnee
{hyp}
{ignore-deprecated-or-unknown-option-in-pdf-version}
{pdfnumcopies}
{\pdf_version:}
}
}
,pdfpagelayout .choices:nn =
{ SinglePage, OneColumn, TwoColumnLeft, TwoColumnRight, TwoPageLeft, TwoPageRight}
{ \pdfmanagement_add:nne {Catalog} { PageLayout }{ /#1 } }
,pdfpagelayout / .code:n =
{ \pdfmanagement_remove:nn {Catalog} { PageLayout } }
,pdfpagelayout / unknown .code:n =
{
\msg_warning:nneee { 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:nne {Catalog} { PageMode }{ /#1 } }
,pdfpagemode / UseAttachments .code:n =
{
\pdf_version_compare:NnTF > {1.5}
{
\pdfmanagement_add:nne {Catalog} { PageMode }{ /UseAttachments }
}
{
\msg_warning:nnee
{hyp}
{ignore-deprecated-or-unknown-value-in-pdf-version}
{UseAttachments}
{\pdf_version:}
}
}
,pdfpagemode .initial:n = { UseOutlines } %for now ...
,pdfpagemode / unknown .code:n =
{
\msg_warning:nneee { 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 {#1} %or blank?
{
\pdfmanagement_remove:nn {Pages} { CropBox }
}
{
\pdfmanagement_add:nne {Pages} { CropBox } { [#1] }
}
}
,pdfpicktraybypdfsize .choice:
,pdfpicktraybypdfsize / true .code:n =
{
\pdf_version_compare:NnTF > {1.6}
{
\pdfmanagement_add:nnn {Catalog / ViewerPreferences }
{ PickTrayByPDFSize } { true }
}
{
\msg_warning:nnee
{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:nnee
{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:nnee { hyp } { no-bool }
{ picktraybypdfsize }
{ \exp_not:n {#1} }
}
,pdfprintarea .choices:nn =
{ MediaBox, CropBox, BleedBox, TrimBox, ArtBox }
{
\pdf_version_compare:NnTF < {2.0}
{
\pdfmanagement_add:nne {Catalog / ViewerPreferences }
{ PrintArea } { /#1 }
}
{
\msg_warning:nnee
{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:nneee { 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:nne {Catalog / ViewerPreferences }
{ PrintClip } { /#1 }
}
{
\msg_warning:nnee
{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:nneee
{ 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:nne {Catalog / ViewerPreferences }
{PrintPageRange}{[#1]}
}
}
{
\msg_warning:nnee
{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:nne {Catalog / ViewerPreferences }
{ PrintScaling } { /#1 }
}
{
\msg_warning:nnee
{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:nneee { hyp } { unknown-choice+empty }
{ pdfprintarea }
{ None, AppDefault }
{ \exp_not:n {#1} }
}
,pdfremotestartview .code:n =
{
\tl_set:Ne \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:Ne \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:Ne \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:nne {Catalog} { OpenAction }
{
[\pdf_pageobject_ref:n {\g_@@_dest_pdfstartpage_tl}~/\g_@@_dest_pdfstartview_tl]
}
}
}
,pdfstartpage .initial:n =1
,pdfstartview .code:n =
{
\tl_set:Ne \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:Ne \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:nne {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:nnee { 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:nnee
{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:nneee { 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:nnee
{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:nneee { 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:nnee { 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 }
{
,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:Ne \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 }
{
,pdflang .code:n =
{
\tl_if_empty:nF { #1 }
{
\pdfmanagement_add:nne {Catalog} { Lang } { (#1) }
\AddToDocumentProperties[document]{lang}{#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 metadata container, so that hyperxmp can
% use them. Creator and Producer can't be removed with the pdfmanagement,
% but we allow to set an empty value.
% If the value begin with an optional argument, we assume a multilanguage clist and
% use only the first value.
% The values are expanded with \cs{text_expand:n}
% \begin{macrocode}
\regex_new:N\l_@@_optlang_regex
\regex_set:Nn\l_@@_optlang_regex {\A\[([A-Za-z\-]+)\](.*)}
\cs_generate_variant:Nn\clist_item:nn{on}
\cs_new_protected:Npn \@@_setup_info_key:nn #1 #2
{
\keys_define:nn { hyp }
{
pdf#1 .code:n =
{
\tl_set:Ne\l_@@_tmpa_tl {\text_expand:n{##1}}
\@@_store_metadata:no {pdf#1}{\l_@@_tmpa_tl}
\tl_if_empty:NTF \l_@@_tmpa_tl
{
\str_case:nnF { #1 }
{
{creator}
{
\msg_info:nnn { hyp }{ empty-info-value } { pdfcreator }
\pdfmanagement_add:nne {Info}{Creator}{()}
}
{producer}
{
\msg_info:nnn { hyp }{ empty-info-value } { pdfproducer }
\pdfmanagement_add:nne {Info}{Producer}{()}
}
}
{
\pdfmanagement_remove:nn {Info}{#2}
}
}
{
\tl_set:Ne\l_@@_tmpb_tl {\clist_item:on{\l_@@_tmpa_tl}{1}}
\exp_args:NNV
\regex_extract_once:NnN \l_@@_optlang_regex \l_@@_tmpb_tl\l_@@_tmpa_seq
\seq_if_empty:NTF\l_@@_tmpa_seq
{
\@@_text_pdfstring_info:oN {\l_@@_tmpa_tl}\l_@@_tmpa_str
}
{
\@@_text_pdfstring_info:eN {\seq_item:Nn \l_@@_tmpa_seq{3}}\l_@@_tmpa_str
}
\str_if_eq:VnF\l_@@_tmpa_str{}
{
\pdfmanagement_add:nne {Info}{#2}{\l_@@_tmpa_str}
}
}
}
}
\keys_define:nn { hyp / info }
{
#2 .code:n =
{
\tl_set:Ne\l_@@_tmpa_tl {\text_expand:n{##1}}
\@@_store_metadata:eo {pdf\str_lowercase:n{#1}}{\l_@@_tmpa_tl}
\tl_if_blank:nTF {##1}
{
\pdfmanagement_remove:nn {Info}{#2}
}
{
\@@_text_pdfstring_info:oN {\l_@@_tmpa_tl}\l_@@_tmpa_str
\str_if_eq:VnF\l_@@_tmpa_str{}
{
\pdfmanagement_add:nne {Info}{#2}{\l_@@_tmpa_str}
}
}
}
,unknown .code:n =
{
\@@_text_pdfstring_info:eN {##1}\l_@@_tmpa_str
\str_if_eq:VnF\l_@@_tmpa_str{}
{
\exp_args:Nno
\pdfmanagement_add:nne {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,pdfmetadate}
% 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 }
{
pdf#1 .code:n =
{
\tl_if_blank:nTF {##1}
{
\pdfmanagement_remove:nn {Info}{#2}
}
{
\pdfmanagement_add:nne {Info}{#2}{(##1)}
}
\@@_store_metadata:nn {pdf#1}{##1}
\AddToDocumentProperties[document]{#1}{##1}
}
}
\keys_define:nn { hyp / info }
{
#2 .code:n =
{
\tl_if_blank:nTF {##1}
{
\pdfmanagement_remove:nn {Info}{#2}
}
{
\pdfmanagement_add:nne {Info}{#2}{(##1)}
}
\exp_args:Ne \@@_store_metadata:nn {pdf\str_lowercase:n{#1}}{##1}
}
}
}
\@@_setup_info_date_key:nn {creationdate} {CreationDate}
\@@_setup_info_date_key:nn {moddate} {ModDate}
\keys_define:nn { hyp }
{
pdfmetadate .code:n = { \@@_store_metadata:nn {pdfmetadate}{#1} }
}
% \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 }
{
,pdftrapped .code:n =
{
\exp_args:Nne
\keys_set:nn { hyp } { _pdftrapped = \str_uppercase:n { #1 } }
}
,_pdftrapped .choices:nn = {TRUE,FALSE,UNKNOWN}
{
\pdfmanagement_add:nne {Info}{Trapped}
{/
\str_uppercase:f { \str_head:n { #1 } }
\str_lowercase:f { \str_tail:n { #1 } }
}
\@@_store_metadata:ne {pdftrapped}
{
\str_uppercase:f { \str_head:n { #1 } }
\str_lowercase:f { \str_tail:n { #1 } }
}
}
,_pdftrapped / unknown .code:n =
{
\msg_warning:nneee { 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 }
{
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} {pdfcreator = LaTeX~with~hyperref}
\keys_set:nn { hyp} {pdfauthor = }
\keys_set:nn { hyp} {pdftitle = }
\keys_set:nn { hyp} {pdfsubject = }
% \end{macrocode}
%
% \subsection{hyperxmp keys}
% hyperxmp defines lots of keys for \cs{hypersetup}.
% They now longer work with this driver. So we provide most of them,
% but they are only stored as metadata:
% \begin{macrocode}
\clist_map_inline:nn
{
,pdfcopyright
,pdftype
,pdflicenseurl
,pdfauthortitle
,pdfcaptionwriter
,pdfmetalang
,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 }
{
#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 }
{
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 \pkg{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 }
{
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:ne { dict }
{
\pdfdict_use:n {l_@@_page/Trans}
}
\pdfmanagement_add:nne {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:nneee { 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}{ Dm }{/#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:nneee { 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:nneee { 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:nneee { 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:Nne\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 }{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\@empty
\let\HyField@cofields\@empty
\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_@@_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_@@_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:Ne\HyField@@AddToFields
{
\pdfannot_box_ref_last:
}
\ifx\Fld@calculate@code\@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
\def\@Form[#1]
{
\kvsetkeys{Form}{#1}
\pdf@ifdraftmode{}
{
\Hy@FormObjects
\prop_map_inline:Nn \g_@@_AcroForm_Fields_prop
{
\pdfmanagement_add:nne { Catalog / AcroForm } { Fields }{##1}
%\pdfmanagement_show:n { Catalog / AcroForm }
}
\prop_if_empty:NF \g_@@_AcroForm_CoFields_prop
{
\prop_map_inline:Nn \g_@@_AcroForm_CoFields_prop
{
\seq_put_right:Nn \l_@@_tmpa_seq {##1}
}
\seq_sort:Nn \l_@@_tmpa_seq
{
\str_compare:nNnTF {##1} > {##2}
{ \sort_return_swapped: }
{ \sort_return_same: }
}
\seq_map_inline:Nn \l_@@_tmpa_seq
{
\pdfmanagement_add:nne { Catalog / AcroForm }
{ CO }
{
\prop_item:Nn \g_@@_AcroForm_CoFields_prop {##1}
}
}
}
\pdfmanagement_add:nne {Catalog / AcroForm/DR/Font }
{ZaDb} {\pdf_object_ref:n {@@/Font/ZaDb} }
\pdfmanagement_add:nne {Catalog / AcroForm/DR/Font }
{Helv} {\pdf_object_ref:n {@@/Font/Helv} }
\pdfmanagement_add:nne {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}
}
}
}
\ExplSyntaxOff
\let\@endForm\@empty
\let\HyAnn@AbsPageLabel\@empty
\let\Fld@pageobjref\@empty
\ExplSyntaxOn
\newcount\HyAnn@Count
\HyAnn@Count=\z@
\def\HyAnn@AbsPageLabel
{
\global\advance\HyAnn@Count by\@ne
%\zref@labelbyprops{HyAnn@\the\HyAnn@Count}{abspage}%
%\zref@labelbylist {HyAnn@\the\HyAnn@Count} {l3pdf}
%\zref@refused{HyAnn@\the\HyAnn@Count}%
\@@_property_record:ee {HyAnn@\the\HyAnn@Count}{abspage}
\property_ref_undefined_warn:ee {HyAnn@\the\HyAnn@Count}{abspage}
}%
\prg_generate_conditional_variant:Nnn \property_if_recorded:nn {ee} {T}
\def\Fld@pageobjref
{
\property_if_recorded:eeT {HyAnn@\the\HyAnn@Count}{abspage}
{
/P~\pdf_pageobject_ref:e
{
\property_ref:ee{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\@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
}
\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
\pdfxform_if_exist:nF { @@_xform_Ding }
{
\pdfxform_new:nnn { @@_xform_Ding } {}
{
\group_begin:
\fontfamily{pzd}
\fontencoding{U}
\fontseries{m}
\fontshape{n}
\selectfont
\char123
\group_end:
}
}
\pdfannot_box:nnne
{\Fld@width}
{\Fld@height}
{0pt} %is this correct?
{
\PDFForm@Radio
/AP
<<
/N
<<
/\@currValue\c_space_tl \pdfxform_ref:n {@@_xform_Ding}
%/Off \c_space_tl \pdfxform_ref:n {@@_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}}
\pdfxform_if_exist:nF
{ @@_xform_Submit }
{
\pdfxform_new:nnn { @@_xform_Submit }{}
{
\fbox{\color_select:n{yellow}\textsf{Submit}}
}
\pdfxform_new:nnn { @@_xform_SubmitP }{}
{
\fbox{\color_select:n{yellow}\textsf{SubmitP}}
}
}
\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 {@@_xform_Submit}~
/D~\pdfxform_ref:n {@@_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
\pdfxform_if_exist:nF { @@_xform_CheckMarkYes }
{
\pdfxform_new:nnn
{@@_xform_CheckMarkYes}{}
{
\group_begin:
\fontfamily{pzd}
\fontencoding{U}
\fontseries{m}
\fontshape{n}
\selectfont
\char51
\group_end:
}
\pdfxform_new:nnn
{@@_xform_CheckMarkOff}{}
{
\group_begin:
\fontfamily{pzd}
\fontencoding{U}
\fontseries{m}
\fontshape{n}
\selectfont
\phantom{\char51} %perhaps xetex needs some small glyph ..
\group_end:
}
}
\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:n {@@/Encoding/pdfdoc }
\pdf_object_new:n {@@/Font/ZaDb }
\pdf_object_new:n {@@/Font/Helv }
\pdf_object_write:nne {@@/Encoding/pdfdoc } { dict }
{
/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:nnn {@@/Font/ZaDb } { dict }
{
/Type/Font
/Subtype/Type1
/Name/ZaDb
/BaseFont/ZapfDingbats
}
\pdf_object_write:nne {@@/Font/Helv } { dict }
{
/Type/Font
/Subtype/Type1
/Name/Helv
/BaseFont/Helvetica
/Encoding~\pdf_object_ref:n { @@/Encoding/pdfdoc }
}
\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
\Hy@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<>%
\fi
\ifx\Fld@format@code\@empty
\else
/F<>%
\fi
\ifx\Fld@validate@code\@empty
\else
/V<>%
\fi
\ifx\Fld@calculate@code\@empty
\else
/C<>%
\fi
\ifx\Fld@onfocus@code\@empty
\else
/Fo<>%
\fi
\ifx\Fld@onblur@code\@empty
\else
/Bl<>%
\fi
\ifx\Fld@onmousedown@code\@empty
\else
/D<>%
\fi
\ifx\Fld@onmouseup@code\@empty
\else
/U<>%
\fi
\ifx\Fld@onenter@code\@empty
\else
/E<>%
\fi
\ifx\Fld@onexit@code\@empty
\else
/X<>%
\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<>
/AP
<<
/N
<<
/Yes~\pdfxform_ref:n{@@_xform_CheckMarkYes}
/Off~\pdfxform_ref:n{@@_xform_CheckMarkOff}
>>
>>
/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<>
\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<>
\Fld@additionalactions
}
\ExplSyntaxOff
\def\PDFForm@List{%
/Subtype/Widget%
\Fld@annotflags
\Fld@pageobjref
\Fld@annotnames
/FT/Ch%
\Fld@flags
/Q \Fld@align
/BS<>%
\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<>
/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 appearance dict make sense here?
\def\PDFForm@Text
{
/Subtype/Widget
~\Fld@annotflags
~\Fld@pageobjref
~\Fld@annotnames
/FT/Tx
~\Fld@flags
/Q~\Fld@align
/BS<>
\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<>%
\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<>%
/A<>%
\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
}%
}
\@ifundefined{hyper@nopatch@sectioning}
{
\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}%
}
\@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
\@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'.
%
% \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:cn { c_@@_colorscheme_primary-colors_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}
}
%
% \end{macrocode}
% \end{implementation}
% \newpage
% \PrintIndex