% \iffalse meta-comment % %% File: l3pdfannot.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 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[full]{l3doc} \usepackage{array,booktabs} \hypersetup{pdfauthor=The LaTeX Project, pdftitle=l3pdfannot (LaTeX PDF management testphase bundle)} \begin{document} \DocInput{\jobname.dtx} \end{document} % % \fi % \providecommand\hook[1]{\texttt{#1}} % \title{^^A % The \pkg{l3pdfannot} module\\ Commands for PDF annotations ^^A % \\ \LaTeX{} PDF management testphase bundle % } % % \author{^^A % The \LaTeX{} Project\thanks % {^^A % E-mail: % \href{mailto:latex-team@latex-project.org} % {latex-team@latex-project.org}^^A % }^^A % } % % \date{Version 0.96h, released 2024-04-09} % % \maketitle % \begin{documentation} % % \section{\pkg{l3pdfannot} documentation} % This module contains a number of commands to create PDF annotations. % The commands are \emph{not} always simple wrappers around primitive commands. % To allow external packages to configure links and other annotations, % some of the commands have hooks and use shared attribute dictionaries. % For these commands the hooks and dictionaries are selected depending on the \meta{type} % of the annotation. Currently the module only supports some general commands % and link annotations. Commands for other annotations like widgets will be added % later. % % \subsection{dvips specialities} % With most engines and backend the content of arguments like \Arg{annot spec} % are dictionaries with keys and values which looks like the PDF. % With dvips this is different. As it write at first a postscript file which is % then interpreted along the rule of the pdfmark reference (and the rules of the postscript % language) the handling is in some parts so different that it is difficult to hide % this in abstraction like the one of this module. % And there is the additional complication that the % two postscript processor ghostscript (ps2pdf) and distiller handles some code differently too. % % For now the following differences have been spotted, it is yet not quite clear % how to resolve them % \begin{itemize} % \item distiller doesn't like it if the action is provided by directly % providing the |/A| key with some values. % Instead it expects a keyword \texttt{/Action}, which it will % then translate to |/A|. For |GoTo| links this has been resolved at the backend level, % but for other link types this problem is open. % \item ghostscript doesn't like object references as values in some places. % The work around here (which is e.g. used by hyperref for GoToR link) is to % write the whole dictionary first as an object and to use its reference, but this % is something distiller doesn't like, sigh. % \item How to escaping text and create unicode can be different. % \end{itemize} % % % % \subsection{General annotation commands} % % \begin{function}[added = 2019-09-05, updated = 2020-04-14] % { \pdfannot_box:nnnn,\pdfannot_box:nnne } % \begin{syntax} % \cs{pdfannot_box:nnnn} \Arg{width} \Arg{height} \Arg{depth} \Arg{annot spec} % \end{syntax} % This creates an \texttt{/Type/Annot} object with the given dimensions. % It doesn't use hooks or dictionaries. The annotation doesn't occupy space but % as it is a whatsit it can affect spacing. % \end{function} % % \begin{function}[added = 2019-09-05] % { \pdfannot_box_ref_last: } % \begin{syntax} % \cs{pdfannot_box_ref_last:} % \end{syntax} % This retrieves the object reference of the last box annotation created. % \end{function} % \subsection{Dictionary for the annotation spec} % % \meta{annot spec} in the above command can be given in two ways. One way is % to enter the needed dictionary keys and values directly: % \begin{verbatim} % \pdfannot_box:nnnn{1cm}{1cm}{0cm}{/Subtype/Link /Border[0~0~1]} % \end{verbatim} % % A second method is to make use of the dictionary commands provided by \pkg{l3pdfdict}: % % \begin{verbatim} % \pdfdict_new:n {l_my_annot} % \pdfdict_put:nnn{l_my_annot}{Subtype}{/Link} % \pdfdict_put:nnn{l_my_annot}{Border}{[0~0~1]} % \pdfannot_box:nnne{1cm}{1cm}{0cm}{\pdfdict_use:n{l_my_annot}} % \end{verbatim} % % The second method is clearly slower and more to type. But it has the advantage % that using such a dictionary makes it easy to add, remove and change entries. % It also avoids the potential problem that a key is added twice with different % values. This allows to create user interfaces to change settings and % also makes it easy to extend the interfaces in case some new setting % should be included. For these reasons both the PDF management itself, % but also the specific annotation commands in the following sections % all make use of such dictionaries. % % \subsection{Link annotations} % Link annotations are special cases of annotations. In the PDF they are identified % by an |/Subtype/Link| entry in the dictionary. % Link annotations are quite important as many documents contain links, % both internal and external. They need a set of special commands for two reasons: % % At first the content of links are not only boxes. Links can contain line % and page breaks (this is normally implemented by the primitive command by % creating a set of annotations). % % At second link annotations are objects that need some % \enquote{management} as more than one % package wants to configure their look and behaviour. % For example \pkg{hyperref}, \pkg{ocgx2} and the code for tagged PDF (currently % in \pkg{tagpdf}) all want to add keys and values to the dictionaries of % link annotation and code around links. % So commands to create link annotations should offer suitable hooks. % There are three standard places in a link where such hooks are needed: % At the begin (for example for a structure command or color), % in the \emph{attr spec} dictionary of the link (for example for the border), and % at the end of the link (to close a structure or the color group). % For the begin and end hooks of the LaTeX hook management are predefined and used. % To add and remove values from the \emph{attr spec} dictionary special % commands described below are provided. The link commands switch to horizontal mode % as the commands of pdftex and luatex can't be used in vertical mode. % % \begin{variable}{\c_pdfannot_link_types_seq} % There are currently five link types, \texttt{URI}, \texttt{GoToR}, % \texttt{Launch}, \texttt{GoTo} or \texttt{Named}, and there are stored in this % constant. % \end{variable} % \begin{variable} % { % pdfannot/link/TYPE/before, % pdfannot/link/TYPE/begin, % pdfannot/link/TYPE/end, % pdfannot/link/TYPE/after % } % These are the hooks used by the following commands. TYPE can be one of % \texttt{URI}, \texttt{GoToR}, % \texttt{Launch}, \texttt{GoTo} or \texttt{Named} % \end{variable} % \begin{variable} % { % link/TYPE % } % These is the name of the dictionary used by the following commands. TYPE can be one of % \texttt{URI}, \texttt{GoToR}, % \texttt{Launch}, \texttt{GoTo} or \texttt{Named}. The dictionary can be changed % by the commands \cs{pdfannot_dict_put:nnn} and friends described below. % \end{variable} % \begin{function}[added = 2020-03-12, updated = 2020-12-06] % { \pdfannot_link:nnn,\pdfannot_link:nen } % \begin{syntax} % \cs{pdfannot_link:nnn} \Arg{type} \Arg{user action spec} \Arg{link text} % \end{syntax} % This creates a link around the \meta{link text}. % \texttt{/Subtype/Link} is added automatically through the dictionary. % \meta{user action spec}\footnote{The wording follows the pdftex documentation}. % is provided as a fast method to add dictionary contents, % but it should be noted that no provision is taken to avoid clashes with % values added through the dictionary. If needed clashing entries should be % removed from the dictionary first. Normally the argument is not needed, all % entries can be added through the dictionary too. % \meta{type} should be one of \texttt{URI}, \texttt{GoToR}, % \texttt{Launch}, \texttt{GoTo} or \texttt{Named}. The |GoTo| variant does % \emph{not} complain if the destination name is not known like % \cs{pdfannot_link_goto_begin:nw}. % The attributes stored in the local dictionary % \texttt{link/}\meta{type} are inserted as % \emph{attr spec} before \meta{user action spec}. % The code in the begin and end hook % \texttt{pdfannot/link/\meta{type}/before} % and \texttt{pdfannot/link/\meta{type}/after} % is executed before and after the link (outside the link command) % while \texttt{pdfannot/link/\meta{type}/begin} % and \texttt{pdfannot/link/\meta{type}/end} are directly around the link % text. None of the hooks introduce a group. % \meta{type} should normally be identical to the value of the |/S| key % in the action dictionary. % As example either with a direct action % \begin{verbatim} % \pdfannot_link:nnn { URI } % { % /A<< % /Type/Action % /S/URI % /URI(https://www.latex-project.org) % >> % } % { link text} % \end{verbatim} % Or through a dictionary: % \begin{verbatim} % \pdfdict_new:n {l_my_action_dict} % \pdfdict_put:nnn {l_my_action_dict}{Type}{/Action} % \pdfdict_put:nnn {l_my_action_dict}{S}{/URI} % \pdfdict_put:nnn {l_my_action_dict}{URI}{(https://www.latex-project.org)} % % \pdfannot_dict_put:nnn % {link/URI} { C } {[1~0~0]} %red border % % \pdfannot_link:nen { URI } % { % /A <<\pdfdict_use:n{l_my_action_dict}>> % } % { link text } % \end{verbatim} % % Or if you want to exclude the possibility of a duplicated /A entry % (if the action is already in the link/GoTo dictionary e.g. if you can expect % other packages to add a dictionary). An alternative is to ensure that % no /A is there by removing it explicitly. % % \begin{verbatim} % \pdfdict_new:n {l_my_action_dict} % \pdfdict_put:nnn {l_my_action_dict}{Type}{/Action} % \pdfdict_put:nnn {l_my_action_dict}{S}{/URI} % \pdfdict_put:nnn {l_my_action_dict}{URI}{(https://www.latex-project.org)} % % % \pdfannot_dict_put:nnn % {link/URI} { C } {[1~0~0]} %red border % % \group_begin: % \pdfannot_dict_put:nne {link/GoTo}{A}{<<\pdfdict_use:n{l_my_action_dict}>>} % \pdfannot_link:nnn { URI }{}{ link text } % \group_end: % \end{verbatim} % % % \end{function} % \begin{function}[updated = 2020-12-06]{ \pdfannot_link_begin:nnw, \pdfannot_link_end:n } % \begin{syntax} % \cs{pdfannot_link_begin:nnw} \Arg{type} \Arg{user action spec} \meta{content} % \cs{pdfannot_link_end:n} \Arg{type} % \end{syntax} % This creates a link like the previous command. % \texttt{/Subtype/Link} is added automatically through the dictionary. % \meta{user action spec}\footnote{The wording follows the pdftex documentation}. % is provided as a fast method to add dictionary contents, % but it should be noted that no provision is taken to avoid clashes with % values added through the dictionary. If needed clashing entries should be % removed from the dictionary first. Normally the argument is not needed, all % entries can be added through the dictionary too. % \texttt{/Subtype/Link} is added automatically. % In contrast to \cs{pdfannot_link:nnn} this function % does not absorb the argument when finding the \meta{content}, and so can % be used in circumstances where the \meta{content} may not be a simple % argument. But beside this, it works similar and use the same hooks. % As example % \begin{verbatim} % \pdfannot_link_begin:nnw { URI } % { % /A<< % /Type/Action % /S/URI % /URI(https://www.latex-project.org) % >> % } % link text % \pdfannot_link_end:n { URI } % \end{verbatim} % \end{function} % \begin{function}[updated = 2020-12-06]{ \pdfannot_link_goto_begin:nw, \pdfannot_link_goto_end: } % \begin{syntax} % \cs{pdfannot_link_goto_begin:nw} \Arg{destination} \meta{content} % \cs{pdfannot_link_goto_end:} % \end{syntax} % This is a special, shorter version for links to internal destinations. It always % uses the hooks and dictionary of the |GoTo| link type. \meta{destination} is a % destination name. In difference to |\pdfannot_link:nnn { GoTo }| it will complain if % \meta{destination} is an unknown destination and give the message % % |name{ZZZZ} has been referenced but does not exist, replaced by a fixed one| % % \end{function} % \begin{function}[added = 2021-02-14]{ \pdfannot_link_ref_last: } % This retrieves the object reference a link created previously with the commands % above. This doesn't work currently with xelatex but a feature request has % been made. see https://tug.org/pipermail/dvipdfmx/2020-December/000134.html % \end{function} % \begin{function}[added = 2021-02-14]{ \pdfannot_ref_last: } % This retrieves the object reference a previously annotation % created either with a link or a general box command. When the last was a link % it won't work with xelatex. % see https://tug.org/pipermail/dvipdfmx/2020-December/000134.html % \end{function} % \begin{NOTE}{UF} % only annot link or also annot? % \end{NOTE} % \begin{function}[added = 2020-03-12]{ \pdfannot_link_margin:n } % \begin{syntax} % \cs{pdfannot_link_margin:n} \Arg{dimen} % \end{syntax} % This sets the dimension of the link margin. % \end{function} % % \begin{function}[added=2021-08-19]{\pdfannot_link_off:,\pdfannot_link_on:} % In most engines links can broken over lines and pages. The backends then create % intermediate link objects to catch all the content between the start and end of % the links, mostly based on some heuristics using the boxlevel. This can % lead to the unpleasant result that header and footer are part of the link too. % Since texlive 2021 pdflatex and lualatex has commands similar to a special already % included in dvipdfmx which allows to interrupt a link. The commands must be used % with care: typically they must be outside a box that would be catched by link to % have the wanted effect. % % \end{function} % \begin{function}[added = 2020-12-04]{ \pdfannot_dict_put:nnn } % \begin{syntax} % \cs{pdfannot_dict_put:nnn} \Arg{dictionary name} \Arg{key} \Arg{value} % \end{syntax} % This adds (locally) a key-value to the internal annot dictionaries used % by the link commands above. % \meta{dictionary name} should be currently one of \texttt{link/URI}, % \texttt{link/URI},\texttt{link/GoToR}, \texttt{link/Launch}, % \texttt{link/GoTo}, \texttt{link/Named}. % \end{function} % \begin{function}[added = 2020-12-04]{ \pdfannot_dict_remove:nn } % \begin{syntax} % \cs{pdfannot_dict_remove:nn} \Arg{dictionary name} \Arg{key} % \end{syntax} % This removes a key-value from the internal annot dictionary % \meta{dictionary name} should be currently one of % \texttt{link/URI}, \texttt{link/GoToR}, \texttt{link/Launch}, % \texttt{link/GoTo}, \texttt{link/Named}. % \end{function} % \begin{function}[added = 2020-12-04]{ \pdfannot_dict_show:n } % \begin{syntax} % \cs{pdfannot_dict_show:n} \Arg{dictionary name} % \end{syntax} % This shows the content of the internal annot dictionary. % \meta{dictionary name} should be currently one of \texttt{link/URI}, % \texttt{link/URI}, \texttt{link/GoToR}, \texttt{link/Launch}, % \texttt{link/GoTo}, \texttt{link/Named}. % \end{function} % % \begin{function}[EXP,added = 2021-03-03] % { \pdfannot_dict_use:n } % \begin{syntax} % \cs{pdfannot_dict_use:n} \Arg{dictionary name} % \end{syntax} % This outputs the property list of the dictionary as a list of % |/key value| pairs. % This can be used e.g. when writing a dictionary object with % \cs{pdf_object_write:nne} % \end{function} % % \begin{variable}[added = 2020-12-28]{\l_pdfannot_F_bitset} % This is a bitset variable, with the named index names suitable for the % /F flag in an annotation. % It can be used for example like this: % \begin{verbatim} % \bitset_set_true:Nn \l_pdfannot_F_bitset {Print} % \pdfannot_dict_put:nne {link/URI} {F} % { \bitset_to_arabic:N \l_pdfannot_F_bitset } % \end{verbatim} % The known keys for the bitset are |Invisible|, |Hidden|, % |Print|, |NoZoom|, |NoRotate|, |NoView|, |ReadOnly|, |Locked|, |ToggleNoView|, % |LockedContents| which correspond to the names used in the PDF references. % \end{variable} % \subsection{Widget annotations} % Widget annotations are quite important for form fields, as they are used % to build the actually instance of such fields. % % As they can contain meaningful content hooks are probably needed to allow tagging % and other manipulations, so like with link special commands are provided. % Widget are normally in a box and line and page breaks are not relevant, so % the command is offered as box command. % % \begin{function}[added = 2021-03-02] % { \pdfannot_widget_box:nnn } % \begin{syntax} % \cs{pdfannot_widget_box:nnn} \Arg{width} \Arg{height} \Arg{depth} % \end{syntax} % This creates an \texttt{/Type/Annot} object with the given dimensions. % The annotation doesn't occupy space. % It will insert the attribute dictionary of the widget type (which % is prefilled with \texttt{/Subtype/Widget}). % The hooks \texttt{pdfannot/widget/before} and \texttt{pdfannot/widget/after} % are executed before and after the widget. % The widget has four subdirectories, |widget/AA|, |widget/AP|, |widget/MK| and % |widget/BS| % which can be filled with \cs{pdfannot_dict_put:nnn} and will be used if not % empty. % % \end{function} % \end{documentation} % % \begin{implementation} % % \section{\pkg{l3pdfannot} implementation} % % \begin{macrocode} %<@@=pdfannot> %<*header> \ProvidesExplPackage{l3pdfannot}{2024-04-09}{0.96h} {PDF-annotations} \RequirePackage{l3pdfdict} % % \end{macrocode} % Annotations have a /F flag, we provide a public % bitset for it. % \begin{macrocode} %<*package> \cs_if_exist:NF \bitset_new:Nn { \RequirePackage { l3bitset } } \bitset_new:Nn \l_pdfannot_F_bitset { Invisible = 1, Hidden = 2, Print = 3, NoZoom = 4, NoRotate = 5, NoView = 6, ReadOnly = 7, Locked = 8, ToggleNoView = 9, LockedContents = 10 } % \end{macrocode} % \begin{NOTE}{UF} % The code/naming tries to unify general annotations and the special type of % link under a common name. % regarding naming and relation of annotation commands see % https://github.com/FrankMittelbach/AccessiblePDF/issues/73 % \subsection{Annotations / backend} % The backend commands are in l3backend: % \cs{__pdf_backend_annotation:nnnn} and \cs{__pdf_backend_annotation_last:} % \cs{__pdf_backend_link_begin_user:nnw}, etc % \end{NOTE} % % \subsection{ General Annotations } % \begin{variable} % { \g_@@_use_lastlink_bool } % The pdf engines have two different primitive commands to refer to the last created % annotation: one for links, one for boxed annotation. We use a boolean to decide % which one should be used, so that only one user command is needed. % \begin{macrocode} \bool_new:N \g_@@_use_lastlink_bool % \end{macrocode} % \end{variable} % \begin{NOTE}{UF} % type or not type? Syntax for type? % should there be a version without type? % \end{NOTE} % \begin{macro}{\pdfannot_box:nnnn,\pdfannot_box:nnne,\pdfannot_box_ref_last:} % \begin{macrocode} \cs_new_protected:Npn \pdfannot_box:nnnn #1 #2 #3 #4 { \__pdf_backend_annotation:nnnn {#1}{#2}{#3}{#4} \bool_gset_false:N\g_@@_use_lastlink_bool } \cs_generate_variant:Nn \pdfannot_box:nnnn {nnne,nnnx} \cs_new:Npn \pdfannot_box_ref_last: { \__pdf_backend_annotation_last: } % \end{macrocode} % \end{macro} % \subsection{Annotations, subtype Widget}\label{pdf:annot:widget} % Widgets are typically boxes, so we provide a box command. % A local dictionary \texttt{l_@@/Widget} is used. % It contains like the other dictionaries % the subtype setting (the /Type is added by the backend). % \begin{macrocode} \pdfdict_new:n { l_@@/widget } \pdfdict_new:n { l_@@/widget/AA } \pdfdict_new:n { l_@@/widget/AP } \pdfdict_new:n { l_@@/widget/MK } \pdfdict_new:n { l_@@/widget/BS } \pdfdict_put:nnn { l_@@/widget }{ Subtype }{ /Widget } \hook_new_pair:nn {pdfannot/widget/before} {pdfannot/widget/after} \cs_new_protected:Npn \pdfannot_widget_box:nnn #1 #2 #3 { \hook_use:n { pdfannot/widget/before } \group_begin: \pdfmeta_standard_verify:nT {annot_widget_no_AA} { \pdfdict_if_empty:nF { l_@@/widget/AA } { \pdf_object_unnamed_write:ne {dict}{\pdfdict_use:n{l_@@/widget/AA}} \pdfdict_put:nne { l_@@/widget } {AA} {\pdf_object_ref_last:} } } \pdfdict_if_empty:nF { l_@@/widget/AP } { \pdf_object_unnamed_write:ne {dict}{\pdfdict_use:n{l_@@/widget/AP}} \pdfdict_put:nne { l_@@/widget } {AP} {\pdf_object_ref_last:} } \pdfdict_if_empty:nF { l_@@/widget/MK } { \pdf_object_unnamed_write:ne {dict}{\pdfdict_use:n{l_@@/widget/MK}} \pdfdict_put:nne { l_@@/widget } {MK} {\pdf_object_ref_last:} } \pdfdict_if_empty:nF { l_@@/widget/BS } { \pdf_object_unnamed_write:ne {dict}{\pdfdict_use:n{l_@@/widget/BS}} \pdfdict_put:nne { l_@@/widget } {BS} {\pdf_object_ref_last:} } \pdfannot_box:nnne {#1}{#2}{#3} { \pdfdict_use:n { l_@@/widget} } \hook_use:n { pdfannot/widget/end } \group_end: \bool_gset_false:N\g_@@_use_lastlink_bool } % \end{macrocode} % % \subsection{Annotations, subtype Link}\label{sec:links} % The code assumes that there will be different link types % (currently URI, GoToR, Launch, GoTo, Named, hyperref uses the names % url,file,run,link,menu) and that links of the same type share % the \emph{attr spec} and also the same begin/end % code. The list of link types need to stay restricted and well documented so that % all packages know which types they have to handle. It is stored in a constant % seq. % \begin{NOTE}{UF} % Perhaps a |cite| type will be useful at some time. -- Thinking more about it, % a |cite| type is not sensible. hyperref supports it, but it doesn't fit in. % Commands like cite, gls, acro, footnote and so on should locally change % linkcolor and linkbordercolor. % Probably we will need some commands to add an attribute to all link types % at once. % hyperref commands for the various type: % url |\hyper@linkurl|, % file |\hyper@linkfile|, % run |\@hyper@launch run|, % link |\hyper@link|, |\find@pdflink| % menu |\Acrobatmenu| % \end{NOTE} % \begin{variable}[added = 2020-03-12]{ \c_pdfannot_link_types_seq } % This constant sequence contains the list of currently supported link types % for which hooks and dictionaries exist. % \end{variable} % % \begin{variable} % { % link/TYPE, % pdfannot/link/TYPE/before, % pdfannot/link/TYPE/begin, % pdfannot/link/TYPE/end, % pdfannot/link/TYPE/after % } % These setup the dictionary and the hook pairs. % \begin{macrocode} \seq_const_from_clist:Nn \c_pdfannot_link_types_seq { URI , GoToR , Launch , GoTo, Named } \seq_map_inline:Nn \c_pdfannot_link_types_seq { \pdfdict_new:n { l_@@/link/#1 } \pdfdict_put:nnn { l_@@/link/#1 }{ Subtype }{ /Link } \hook_new_pair:nn {pdfannot/link/#1/before} {pdfannot/link/#1/after} \hook_new_pair:nn {pdfannot/link/#1/begin} {pdfannot/link/#1/end} } % \end{macrocode} % \end{variable} % % \subsection{Interruption of links} % \begin{macrocode} \cs_new_protected:Nn \pdfannot_link_off: { \__pdf_backend_link_off: } \cs_new_protected:Nn \pdfannot_link_on: { \__pdf_backend_link_on: } % \end{macrocode} % % % \subsubsection{Annotations, subtype Link /management} % % \begin{macro}{\pdfannot_link:nnn,\pdfannot_link:nen} % \begin{macrocode} \cs_new_protected:Nn \pdfannot_link:nnn %#1 type (URI, GoTo etc), %#2 action spec, #3 link text { \hook_use:n { pdfannot/link/#1/before} \mode_leave_vertical: \exp_args:Nee %xetex needs expansion \__pdf_backend_link_begin_user:nnw { \pdfdict_if_exist:nT { l_@@/link/#1 } { \pdfdict_use:n { l_@@/link/#1} } } { #2 %exp_not? } \bool_gset_true:N \g_@@_use_lastlink_bool \hook_use:n { pdfannot/link/#1/begin} #3 \hook_use:n { pdfannot/link/#1/end} \__pdf_backend_link_end: \bool_gset_true:N \g_@@_use_lastlink_bool \hook_use:n { pdfannot/link/#1/after} } \cs_generate_variant:Nn \pdfannot_link:nnn {nen,nxn} % \end{macrocode} % \end{macro} % \begin{macro}{ % \pdfannot_link_begin:nnw, % \pdfannot_link_begin:new, % \pdfannot_link_end:n } % \begin{macrocode} \cs_new_protected:Npn \pdfannot_link_begin:nnw #1 #2 %#1 type, #2 action spec { \hook_use:n { pdfannot/link/#1/before} \mode_leave_vertical: \exp_args:Nee %xetex needs expansion \__pdf_backend_link_begin_user:nnw { \pdfdict_if_exist:nT { l_@@/link/#1 } { \pdfdict_use:n { l_@@/link/#1} } } { #2 } \bool_gset_true:N \g_@@_use_lastlink_bool \hook_use:n { pdfannot/link/#1/begin} } \cs_new_protected:Nn \pdfannot_link_end:n %#1 type, e.g. url { \hook_use:n { pdfannot/link/#1/end} \__pdf_backend_link_end: \bool_gset_true:N \g_@@_use_lastlink_bool \hook_use:n { pdfannot/link/#1/after} } \cs_generate_variant:Nn \pdfannot_link_begin:nnw {new,nxw} % \end{macrocode} % \end{macro} % \begin{macro}{\pdfannot_link_goto_begin:nw, \pdfannot_link_goto_end:} % \begin{macrocode} \cs_new_protected:Npn \pdfannot_link_goto_begin:nw #1 %#1 destination { \pdfdict_remove:nn { l_@@/link/GoTo} {Subtype} \hook_use:n { pdfannot/link/GoTo/before} %the backend add it too \mode_leave_vertical: \exp_args:Nee %xetex needs expansion \__pdf_backend_link_begin_goto:nnw { \pdfdict_use:n { l_@@/link/GoTo} } { #1 } \bool_gset_true:N \g_@@_use_lastlink_bool \pdfdict_put:nnn { l_@@/link/GoTo} {Subtype}{GoTo} \hook_use:n { pdfannot/link/GoTo/begin} } \cs_new_protected:Nn \pdfannot_link_goto_end: { \hook_use:n { pdfannot/link/GoTo/end} \__pdf_backend_link_end: \bool_gset_true:N \g_@@_use_lastlink_bool \hook_use:n { pdfannot/link/GoTo/after} } % \end{macrocode} % \end{macro} % \begin{macro}[EXP]{\pdfannot_link_ref_last:, \pdfannot_ref_last:} % \begin{macrocode} \cs_new:Nn \pdfannot_link_ref_last: { \__pdf_backend_link_last: } % \end{macrocode} % \begin{macrocode} \cs_new:Npn \pdfannot_ref_last: { \bool_if:NTF \g_@@_use_lastlink_bool { \__pdf_backend_link_last: } { \__pdf_backend_annotation_last: } } % \end{macrocode} % \end{macro} % \begin{macro}{ \pdfannot_link_margin:n} % \begin{macrocode} \cs_new_protected:Npn \pdfannot_link_margin:n #1 { \__pdf_backend_link_margin:n { #1 } } % \end{macrocode} % \end{macro} % \begin{macro} % { % \pdfannot_dict_put:nnn, % \pdfannot_dict_put:nne, % \pdfannot_dict_remove:nn, % \pdfannot_dict_show:n % \pdfannot_dict_use:n % } % \begin{macrocode} \cs_new_protected:Npn \pdfannot_dict_put:nnn #1 #2 #3 { \pdfdict_put:nnn { l_@@/#1 } { #2 }{ #3 } } \cs_generate_variant:Nn \pdfannot_dict_put:nnn {nne,nnx} % \end{macrocode} % \begin{macrocode} \cs_new_protected:Npn \pdfannot_dict_remove:nn #1 #2 { \pdfdict_remove:nn { l_@@/#1 } { #2 } } % \end{macrocode} % \begin{macrocode} \cs_new_protected:Npn \pdfannot_dict_show:n #1 { \pdfdict_show:n { l_@@/#1 } } \cs_new:Npn \pdfannot_dict_use:n #1 { \pdfdict_use:n { l_@@/#1 } } % % \end{macrocode} % \end{macro} % \end{implementation} % % \PrintIndex