diff options
Diffstat (limited to 'macros/latex/required/l3backend/l3backend-pdf.dtx')
-rw-r--r-- | macros/latex/required/l3backend/l3backend-pdf.dtx | 1755 |
1 files changed, 1755 insertions, 0 deletions
diff --git a/macros/latex/required/l3backend/l3backend-pdf.dtx b/macros/latex/required/l3backend/l3backend-pdf.dtx new file mode 100644 index 0000000000..cf09c0eec2 --- /dev/null +++ b/macros/latex/required/l3backend/l3backend-pdf.dtx @@ -0,0 +1,1755 @@ +% \iffalse meta-comment +% +%% File: l3backend-pdf.dtx +% +% Copyright (C) 2019-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 +% +% https://www.latex-project.org/lppl.txt +% +% This file is part of the "l3backend 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/latex3 +% +% for those people who are interested. +% +%<*driver> +\documentclass[full,kernel]{l3doc} +\begin{document} + \DocInput{\jobname.dtx} +\end{document} +%</driver> +% \fi +% +% \title{^^A +% The \pkg{l3backend-pdf} module\\ Backend PDF features^^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{Released 2024-04-11} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3backend-pdf} implementation} +% +% \begin{macrocode} +%<*package> +%<@@=pdf> +% \end{macrocode} +% +% Setting up PDF resources is a complex area with only limited documentation +% in the engine manuals. The following code builds heavily on existing ideas +% from \pkg{hyperref} work by Sebastian Rahtz and Heiko Oberdiek, and +% significant contributions by Alexander Grahn, in addition to the specific +% code referenced a various points. +% +% \subsection{Shared code} +% +% A very small number of items that belong at the backend level but which +% are common to most backends. +% +% \begin{macrocode} +%<*!dvisvgm> +% \end{macrocode} +% +% \begin{variable}{\l_@@_internal_box} +% \begin{macrocode} +\box_new:N \l_@@_internal_box +% \end{macrocode} +% \end{variable} +% +% \begin{macrocode} +%</!dvisvgm> +% \end{macrocode} +% +% \subsection{\texttt{dvips} backend} +% +% \begin{macrocode} +%<*dvips> +% \end{macrocode} +% +% \begin{macro}{\@@_backend_pdfmark:n, \@@_backend_pdfmark:e} +% Used often enough it should be a separate function. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_pdfmark:n #1 + { \__kernel_backend_postscript:n { mark #1 ~ pdfmark } } +\cs_generate_variant:Nn \@@_backend_pdfmark:n { e } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Catalogue entries} +% +% \begin{macro}{\@@_backend_catalog_gput:nn, \@@_backend_info_gput:nn} +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_catalog_gput:nn #1#2 + { \@@_backend_pdfmark:n { { Catalog } << /#1 ~ #2 >> /PUT } } +\cs_new_protected:Npn \@@_backend_info_gput:nn #1#2 + { \@@_backend_pdfmark:n { /#1 ~ #2 /DOCINFO } } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Objects} +% +% \begin{macro}{\@@_backend_object_new:} +% \begin{macro}[EXP]{\@@_backend_object_ref:n, \@@_backend_object_id:n} +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_new: + { \int_gincr:N \g_@@_backend_object_int } +\cs_new:Npn \@@_backend_object_ref:n #1 { { pdf.obj #1 } } +\cs_new_eq:NN \@@_backend_object_id:n \@@_backend_object_ref:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \@@_backend_object_write:nnn, \@@_backend_object_write:nne, +% \@@_backend_object_write_aux:nnn +% } +% \begin{macro} +% { +% \@@_backend_object_write_array:nn , +% \@@_backend_object_write_dict:nn , +% \@@_backend_object_write_fstream:nn , +% \@@_backend_object_write_stream:nn +% } +% \begin{macro}{\@@_backend_object_write_stream:nnn} +% This is where we choose the actual type: some work to get things +% right. To allow code sharing with the anonymous version, we use an +% auxiliary. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_write:nnn #1#2#3 + { + \@@_backend_object_write_aux:nnn + { \@@_backend_object_ref:n {#1} } + {#2} {#3} + } +\cs_generate_variant:Nn \@@_backend_object_write:nnn { nne } +\cs_new_protected:Npn \@@_backend_object_write_aux:nnn #1#2#3 + { + \@@_backend_pdfmark:e + { + /_objdef ~ #1 + /type + \str_case:nn {#2} + { + { array } { /array } + { dict } { /dict } + { fstream } { /stream } + { stream } { /stream } + } + /OBJ + } + \use:c { @@_backend_object_write_ #2 :nn } {#1} {#3} + } +\cs_new_protected:Npn \@@_backend_object_write_array:nn #1#2 + { + \@@_backend_pdfmark:e + { #1 ~0~ [ ~ \exp_not:n {#2} ~ ] ~ /PUTINTERVAL } + } +\cs_new_protected:Npn \@@_backend_object_write_dict:nn #1#2 + { + \@@_backend_pdfmark:e + { #1 << \exp_not:n {#2} >> /PUT } + } +\cs_new_protected:Npn \@@_backend_object_write_fstream:nn #1#2 + { + \exp_args:Ne + \@@_backend_object_write_fstream:nnn {#1} #2 + } +\cs_new_protected:Npn \@@_backend_object_write_fstream:nnn #1#2#3 + { + \__kernel_backend_postscript:n + { + SDict ~ begin ~ + mark ~ #1 ~ << #2 >> /PUT ~ pdfmark ~ + mark ~ #1 ~ ( #3 )~ ( r )~ file ~ /PUT ~ pdfmark ~ + end + } + } +\cs_new_protected:Npn \@@_backend_object_write_stream:nn #1#2 + { + \exp_args:Ne + \@@_backend_object_write_stream:nnn {#1} #2 + } +\cs_new_protected:Npn \@@_backend_object_write_stream:nnn #1#2#3 + { + \__kernel_backend_postscript:n + { + mark ~ #1 ~ ( #3 ) /PUT ~ pdfmark ~ + mark ~ #1 ~ << #2 >> /PUT ~ pdfmark + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_object_now:nn, \@@_backend_object_now:ne} +% No anonymous objects, so things are done manually. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_now:nn #1#2 + { + \int_gincr:N \g_@@_backend_object_int + \@@_backend_object_write_aux:nnn + { { pdf.obj \int_use:N \g_@@_backend_object_int } } + {#1} {#2} + } +\cs_generate_variant:Nn \@@_backend_object_now:nn { ne } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_object_last:} +% Much like the annotation version. +% \begin{macrocode} +\cs_new:Npn \@@_backend_object_last: + { { pdf.obj \int_use:N \g_@@_backend_object_int } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_pageobject_ref:n} +% Page references are easy in \texttt{dvips}. +% \begin{macrocode} +\cs_new:Npn \@@_backend_pageobject_ref:n #1 + { { Page #1 } } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Annotations} +% +% In \texttt{dvips}, annotations have to be constructed manually. As such, +% we need the object code above for some definitions. +% +% \begin{variable}{\l_@@_backend_content_box} +% The content of an annotation. +% \begin{macrocode} +\box_new:N \l_@@_backend_content_box +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_backend_model_box} +% For creating model sizing for links. +% \begin{macrocode} +\box_new:N \l_@@_backend_model_box +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_backend_annotation_int} +% Needed as objects which are not annotations could be created. +% \begin{macrocode} +\int_new:N \g_@@_backend_annotation_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_backend_annotation:nnnn} +% Annotations are objects, but we track them separately. Notably, they are +% not in the object data lists. Here, to get the co-ordinates of the +% annotation, we need to have the data collected at the PostScript level. +% That requires a bit of box trickery (effectively a \LaTeXe{} |picture| +% of zero size). Once the data is collected, use it to set up the annotation +% border. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_annotation:nnnn #1#2#3#4 + { + \exp_args:Nf \@@_backend_annotation_aux:nnnn + { \dim_eval:n {#1} } {#2} {#3} {#4} + } +\cs_new_protected:Npn \@@_backend_annotation_aux:nnnn #1#2#3#4 + { + \box_move_down:nn {#3} + { \hbox:n { \__kernel_backend_postscript:n { pdf.save.ll } } } + \box_move_up:nn {#2} + { + \hbox:n + { + \__kernel_kern:n {#1} + \__kernel_backend_postscript:n { pdf.save.ur } + \__kernel_kern:n { -#1 } + } + } + \int_gincr:N \g_@@_backend_object_int + \int_gset_eq:NN \g_@@_backend_annotation_int \g_@@_backend_object_int + \@@_backend_pdfmark:e + { + /_objdef { pdf.obj \int_use:N \g_@@_backend_object_int } + pdf.rect + #4 ~ + /ANN + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_annotation_last:} +% Provide the last annotation we created: could get tricky of course if +% other packages are loaded. +% \begin{macrocode} +\cs_new:Npn \@@_backend_annotation_last: + { { pdf.obj \int_use:N \g_@@_backend_annotation_int } } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\g_@@_backend_link_int} +% To track annotations which are links. +% \begin{macrocode} +\int_new:N \g_@@_backend_link_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_backend_link_dict_tl} +% To pass information to the end-of-link function. +% \begin{macrocode} +\tl_new:N \g_@@_backend_link_dict_tl +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_backend_link_sf_int} +% Needed to save/restore space factor, which is needed to deal with the face +% we need a box. +% \begin{macrocode} +\int_new:N \g_@@_backend_link_sf_int +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_backend_link_math_bool} +% Needed to save/restore math mode. +% \begin{macrocode} +\bool_new:N \g_@@_backend_link_math_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\g_@@_backend_link_bool} +% Track link formation: we cannot nest at all. +% \begin{macrocode} +\bool_new:N \g_@@_backend_link_bool +% \end{macrocode} +% \end{variable} +% +% \begin{variable}{\l_@@_breaklink_pdfmark_tl} +% Swappable content for link breaking. +% \begin{macrocode} +\tl_new:N \l_@@_breaklink_pdfmark_tl +\tl_set:Nn \l_@@_breaklink_pdfmark_tl { pdfmark } +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_breaklink_postscript:n} +% To allow dropping material unless link breaking is active. +% \begin{macrocode} +\cs_new_protected:Npn \@@_breaklink_postscript:n #1 { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_breaklink_usebox:N} +% Swappable box unpacking or use. +% \begin{macrocode} +\cs_new_eq:NN \@@_breaklink_usebox:N \box_use:N +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_link_begin_goto:nnw, \@@_backend_link_begin_user:nnw} +% \begin{macro}{\@@_backend_link:nw, \@@_backend_link_aux:nw} +% \begin{macro}{\@@_backend_link_end:, \@@_backend_link_end_aux:} +% \begin{macro}{\@@_backend_link_minima:} +% \begin{macro}{\@@_backend_link_outerbox:n} +% \begin{macro}{\@@_backend_link_sf_save:, \@@_backend_link_sf_restore:} +% Links are crated like annotations but with dedicated code to allow for +% adjusting the size of the rectangle. In contrast to \pkg{hyperref}, we +% grab the link content as a box which can then unbox: this allows the same +% interface as for \pdfTeX{}. +% +% Notice that the link setup here uses |/Action| not |/A|. That is because +% Distiller \emph{requires} this trigger word, rather than a \enquote{raw} +% PDF dictionary key (Ghostscript can handle either form). +% +% Taking the idea of |evenboxes| from \pkg{hypdvips}, we implement a minimum +% box height and depth for link placement. This means that \enquote{underlining} +% with a hyperlink will generally give an even appearance. However, to ensure +% that the full content is always above the link border, we do not allow +% this to be negative (contrast \pkg{hypdvips} approach). The result should +% be similar to \pdfTeX{} in the vast majority of foreseeable cases. +% +% The object number for a link is saved separately from the rest of the +% dictionary as this allows us to insert it just once, at either an +% unbroken link or only in the first line of a broken one. That makes the +% code clearer but also avoids a low-level PostScript error with the code +% as taken from \pkg{hypdvips}. +% +% Getting the outer dimensions of the text area may be better using a two-pass +% approach and |\tex_savepos:D|. That plus generic mode are still to re-examine. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_begin_goto:nnw #1#2 + { + \@@_backend_link_begin:nw + { #1 /Subtype /Link /Action << /S /GoTo /D ( #2 ) >> } + } +\cs_new_protected:Npn \@@_backend_link_begin_user:nnw #1#2 + { \@@_backend_link_begin:nw {#1#2} } +\cs_new_protected:Npn \@@_backend_link_begin:nw #1 + { + \bool_if:NF \g_@@_backend_link_bool + { \@@_backend_link_begin_aux:nw {#1} } + } +% \end{macrocode} +% The definition of |pdf.link.dict| here is needed as there is code in the +% PostScript headers for breaking links, and that can only work with this +% available. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_begin_aux:nw #1 + { + \bool_gset_true:N \g_@@_backend_link_bool + \__kernel_backend_postscript:n + { /pdf.link.dict ( #1 ) def } + \tl_gset:Nn \g_@@_backend_link_dict_tl {#1} + \@@_backend_link_sf_save: + \mode_if_math:TF + { \bool_gset_true:N \g_@@_backend_link_math_bool } + { \bool_gset_false:N \g_@@_backend_link_math_bool } + \hbox_set:Nw \l_@@_backend_content_box + \@@_backend_link_sf_restore: + \bool_if:NT \g_@@_backend_link_math_bool + { \c_math_toggle_token } + } +\cs_new_protected:Npn \@@_backend_link_end: + { + \bool_if:NT \g_@@_backend_link_bool + { \@@_backend_link_end_aux: } + } +\cs_new_protected:Npn \@@_backend_link_end_aux: + { + \bool_if:NT \g_@@_backend_link_math_bool + { \c_math_toggle_token } + \@@_backend_link_sf_save: + \hbox_set_end: + \@@_backend_link_minima: + \hbox_set:Nn \l_@@_backend_model_box { Gg } + \exp_args:Ne \@@_backend_link_outerbox:n + { + \int_if_odd:nTF { \value { page } } + { \oddsidemargin } + { \evensidemargin } + } + \box_move_down:nn { \box_dp:N \l_@@_backend_content_box } + { \hbox:n { \__kernel_backend_postscript:n { pdf.save.linkll } } } + \@@_breaklink_postscript:n { pdf.bordertracking.begin } + \@@_breaklink_usebox:N \l_@@_backend_content_box + \@@_breaklink_postscript:n { pdf.bordertracking.end } + \box_move_up:nn { \box_ht:N \l_@@_backend_content_box } + { + \hbox:n + { \__kernel_backend_postscript:n { pdf.save.linkur } } + } + \int_gincr:N \g_@@_backend_object_int + \int_gset_eq:NN \g_@@_backend_link_int \g_@@_backend_object_int + \__kernel_backend_postscript:e + { + mark + /_objdef { pdf.obj \int_use:N \g_@@_backend_link_int } + \g_@@_backend_link_dict_tl \c_space_tl + pdf.rect + /ANN ~ \l_@@_breaklink_pdfmark_tl + } + \@@_backend_link_sf_restore: + \bool_gset_false:N \g_@@_backend_link_bool + } +\cs_new_protected:Npn \@@_backend_link_minima: + { + \hbox_set:Nn \l_@@_backend_model_box { Gg } + \__kernel_backend_postscript:e + { + /pdf.linkdp.pad ~ + \dim_to_decimal:n + { + \dim_max:nn + { + \box_dp:N \l_@@_backend_model_box + - \box_dp:N \l_@@_backend_content_box + } + { 0pt } + } ~ + pdf.pt.dvi ~ def + /pdf.linkht.pad ~ + \dim_to_decimal:n + { + \dim_max:nn + { + \box_ht:N \l_@@_backend_model_box + - \box_ht:N \l_@@_backend_content_box + } + { 0pt } + } ~ + pdf.pt.dvi ~ def + } + } +\cs_new_protected:Npn \@@_backend_link_outerbox:n #1 + { + \__kernel_backend_postscript:e + { + /pdf.outerbox + [ + \dim_to_decimal:n {#1} ~ + \dim_to_decimal:n { -\box_dp:N \l_@@_backend_model_box } ~ + \dim_to_decimal:n { #1 + \textwidth } ~ + \dim_to_decimal:n { \box_ht:N \l_@@_backend_model_box } + ] + [ exch { pdf.pt.dvi } forall ] def + /pdf.baselineskip ~ + \dim_to_decimal:n { \tex_baselineskip:D } ~ dup ~ 0 ~ gt + { pdf.pt.dvi ~ def } + { pop ~ pop } + ifelse + } + } +\cs_new_protected:Npn \@@_backend_link_sf_save: + { + \int_gset:Nn \g_@@_backend_link_sf_int + { + \mode_if_horizontal:TF + { \tex_spacefactor:D } + { 0 } + } + } +\cs_new_protected:Npn \@@_backend_link_sf_restore: + { + \mode_if_horizontal:T + { + \int_compare:nNnT \g_@@_backend_link_sf_int > { 0 } + { \int_set_eq:NN \tex_spacefactor:D \g_@@_backend_link_sf_int } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% Hooks to allow link breaking: something will be needed in format mode +% at some stage. At present this code is disabled as there is an open +% question about the name of the hook: to be resolved at the \LaTeXe{} +% end. +% \begin{macrocode} +\use_none:n + { + \cs_if_exist:NT \@makecol@hook + { + \tl_put_right:Nn \@makecol@hook + { + \box_if_empty:NF \l_shipout_box + { + \vbox_set:Nn \l_shipout_box + { + \__kernel_backend_postscript:n + { + pdf.globaldict /pdf.brokenlink.rect ~ known + { pdf.bordertracking.continue } + if + } + \vbox_unpack_drop:N \l_shipout_box + \__kernel_backend_postscript:n + { pdf.bordertracking.endpage } + } + } + } + \tl_set:Nn \l_@@_breaklink_pdfmark_tl { pdf.pdfmark } + \cs_set_eq:NN \@@_breaklink_postscript:n \__kernel_backend_postscript:n + \cs_set_eq:NN \@@_breaklink_usebox:N \hbox_unpack:N + } + } +% \end{macrocode} +% +% \begin{macro}{\@@_backend_link_last:} +% The same as annotations, but with a custom integer. +% \begin{macrocode} +\cs_new:Npn \@@_backend_link_last: + { { pdf.obj \int_use:N \g_@@_backend_link_int } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_link_margin:n} +% Convert to big points and pass to PostScript. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_margin:n #1 + { + \__kernel_backend_postscript:e + { + /pdf.linkmargin { \dim_to_decimal:n {#1} ~ pdf.pt.dvi } def + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_destination:nn} +% \begin{macro}{\@@_backend_destination:nnnn, \@@_backend_destination_aux:nnnn} +% Here, we need to turn the zoom into a scale. We also need to know where +% the current anchor point actually is: worked out in PostScript. For the +% rectangle version, we have a bit more PostScript: we need two points. +% fitr without rule spec doesn't work, so it falls back to \texttt{/Fit} here. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_destination:nn #1#2 + { + \__kernel_backend_postscript:n { pdf.dest.anchor } + \@@_backend_pdfmark:e + { + /View + [ + \str_case:nnF {#2} + { + { xyz } { /XYZ ~ pdf.dest.point ~ null } + { fit } { /Fit } + { fitb } { /FitB } + { fitbh } { /FitBH ~ pdf.dest.y } + { fitbv } { /FitBV ~ pdf.dest.x } + { fith } { /FitH ~ pdf.dest.y } + { fitv } { /FitV ~ pdf.dest.x } + { fitr } { /Fit } + } + { + /XYZ ~ pdf.dest.point ~ \fp_eval:n { (#2) / 100 } + } + ] + /Dest ( \exp_not:n {#1} ) cvn + /DEST + } + } +\cs_new_protected:Npn \@@_backend_destination:nnnn #1#2#3#4 + { + \exp_args:Ne \@@_backend_destination_aux:nnnn + { \dim_eval:n {#2} } {#1} {#3} {#4} + } +\cs_new_protected:Npn \@@_backend_destination_aux:nnnn #1#2#3#4 + { + \vbox_to_zero:n + { + \__kernel_kern:n {#4} + \hbox:n { \__kernel_backend_postscript:n { pdf.save.ll } } + \tex_vss:D + } + \__kernel_kern:n {#1} + \vbox_to_zero:n + { + \__kernel_kern:n { -#3 } + \hbox:n { \__kernel_backend_postscript:n { pdf.save.ur } } + \tex_vss:D + } + \__kernel_kern:n { -#1 } + \@@_backend_pdfmark:n + { + /View + [ + /FitR ~ + pdf.llx ~ pdf.lly ~ pdf.dest2device ~ + pdf.urx ~ pdf.ury ~ pdf.dest2device + ] + /Dest ( #2 ) cvn + /DEST + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Structure} +% +% \begin{macro}{\@@_backend_compresslevel:n} +% \begin{macro}{\@@_backend_compress_objects:n} +% Doable for the usual \texttt{ps2pdf} method. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_compresslevel:n #1 + { + \int_compare:nNnT {#1} = 0 + { + \__kernel_backend_literal_postscript:n + { + /setdistillerparams ~ where + { pop << /CompressPages ~ false >> setdistillerparams } + if + } + } + } +\cs_new_protected:Npn \@@_backend_compress_objects:n #1 + { + \bool_if:nF {#1} + { + \__kernel_backend_literal_postscript:n + { + /setdistillerparams ~ where + { pop << /CompressStreams ~ false >> setdistillerparams } + if + } + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\@@_backend_version_major_gset:n, \@@_backend_version_minor_gset:n} +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_version_major_gset:n #1 + { + \cs_gset:Npe \@@_backend_version_major: { \int_eval:n {#1} } + } +\cs_new_protected:Npn \@@_backend_version_minor_gset:n #1 + { + \cs_gset:Npe \@@_backend_version_minor: { \int_eval:n {#1} } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_version_major:, \@@_backend_version_minor:} +% Data not available! +% \begin{macrocode} +\cs_new:Npn \@@_backend_version_major: { -1 } +\cs_new:Npn \@@_backend_version_minor: { -1 } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Marked content} +% +% \begin{macro}{\@@_backend_bdc:nn} +% \begin{macro}{\@@_backend_emc:} +% Simple wrappers. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_bdc:nn #1#2 + { \@@_backend_pdfmark:n { /#1 ~ #2 /BDC } } +\cs_new_protected:Npn \@@_backend_emc: + { \@@_backend_pdfmark:n { /EMC } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</dvips> +% \end{macrocode} +% +% \subsection{\LuaTeX{} and \pdfTeX{} backend} +% +% \begin{macrocode} +%<*luatex|pdftex> +% \end{macrocode} +% +% \subsubsection{Annotations} +% +% \begin{macro}{\@@_backend_annotation:nnnn} +% Simply pass the raw data through, just dealing with evaluation of dimensions. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_annotation:nnnn #1#2#3#4 + { +%<*luatex> + \tex_pdfextension:D annot ~ +%</luatex> +%<*pdftex> + \tex_pdfannot:D +%</pdftex> + width ~ \dim_eval:n {#1} ~ + height ~ \dim_eval:n {#2} ~ + depth ~ \dim_eval:n {#3} ~ + {#4} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_annotation_last:} +% A tiny amount of extra data gets added here; we use \texttt{x}-type +% expansion to get the space in the right place and form. The \enquote{extra} +% space in the \LuaTeX{} version is \emph{required} as it is consumed in +% finding the end of the keyword. +% \begin{macrocode} +\cs_new:Npe \@@_backend_annotation_last: + { + \exp_not:N \int_value:w +%<*luatex> + \exp_not:N \tex_pdffeedback:D lastannot ~ +%</luatex> +%<*pdftex> + \exp_not:N \tex_pdflastannot:D +%</pdftex> + \c_space_tl 0 ~ R + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% {\@@_backend_link_begin_goto:nnw, \@@_backend_link_begin_user:nnw} +% \begin{macro}{\@@_backend_link_begin:nnnw} +% \begin{macro}{\@@_backend_link_end:} +% Links are all created using the same internals. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_begin_goto:nnw #1#2 + { \@@_backend_link_begin:nnnw {#1} { goto~name } {#2} } +\cs_new_protected:Npn \@@_backend_link_begin_user:nnw #1#2 + { \@@_backend_link_begin:nnnw {#1} { user } {#2} } +\cs_new_protected:Npn \@@_backend_link_begin:nnnw #1#2#3 + { +%<*luatex> + \tex_pdfextension:D startlink ~ +%</luatex> +%<*pdftex> + \tex_pdfstartlink:D +%</pdftex> + attr {#1} + #2 {#3} + } +\cs_new_protected:Npn \@@_backend_link_end: + { +%<*luatex> + \tex_pdfextension:D endlink \scan_stop: +%</luatex> +%<*pdftex> + \tex_pdfendlink:D +%</pdftex> + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_link_last:} +% Formatted for direct use. +% \begin{macrocode} +\cs_new:Npe \@@_backend_link_last: + { + \exp_not:N \int_value:w +%<*luatex> + \exp_not:N \tex_pdffeedback:D lastlink ~ +%</luatex> +%<*pdftex> + \exp_not:N \tex_pdflastlink:D +%</pdftex> + \c_space_tl 0 ~ R + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_link_margin:n} +% A simple task: pass the data to the primitive. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_margin:n #1 + { +%<*luatex> + \tex_pdfvariable:D linkmargin +%</luatex> +%<*pdftex> + \tex_pdflinkmargin:D +%</pdftex> + \dim_eval:n {#1} \scan_stop: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_destination:nn} +% \begin{macro}{\@@_backend_destination:nnnn} +% A simple task: pass the data to the primitive. The |\scan_stop:| deals +% with the danger of an unterminated keyword. The zoom given here is a +% percentage, but we need to pass it as \emph{per mille}. The rectangle +% version is also easy as everything is build in. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_destination:nn #1#2 + { +%<*luatex> + \tex_pdfextension:D dest ~ +%</luatex> +%<*pdftex> + \tex_pdfdest:D +%</pdftex> + name {#1} + \str_case:nnF {#2} + { + { xyz } { xyz } + { fit } { fit } + { fitb } { fitb } + { fitbh } { fitbh } + { fitbv } { fitbv } + { fith } { fith } + { fitv } { fitv } + { fitr } { fitr } + } + { xyz ~ zoom \fp_eval:n { #2 * 10 } } + \scan_stop: + } +\cs_new_protected:Npn \@@_backend_destination:nnnn #1#2#3#4 + { +%<*luatex> + \tex_pdfextension:D dest ~ +%</luatex> +%<*pdftex> + \tex_pdfdest:D +%</pdftex> + name {#1} + fitr ~ + width \dim_eval:n {#2} ~ + height \dim_eval:n {#3} ~ + depth \dim_eval:n {#4} \scan_stop: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Catalogue entries} +% +% \begin{macro}{\@@_backend_catalog_gput:nn, \@@_backend_info_gput:nn} +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_catalog_gput:nn #1#2 + { +%<*luatex> + \tex_pdfextension:D catalog +%</luatex> +%<*pdftex> + \tex_pdfcatalog:D +%</pdftex> + { / #1 ~ #2 } + } +\cs_new_protected:Npn \@@_backend_info_gput:nn #1#2 + { +%<*luatex> + \tex_pdfextension:D info +%</luatex> +%<*pdftex> + \tex_pdfinfo:D +%</pdftex> + { / #1 ~ #2 } + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Objects} +% +% \begin{variable}{\g_@@_backend_object_prop} +% For tracking objects to allow finalisation. +% \begin{macrocode} +\prop_new:N \g_@@_backend_object_prop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_backend_object_new:} +% \begin{macro}[EXP]{\@@_backend_object_ref:n, \@@_backend_object_id:n} +% Declaring objects means reserving at the PDF level plus starting +% tracking. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_new: + { +%<*luatex> + \tex_pdfextension:D obj ~ +%</luatex> +%<*pdftex> + \tex_pdfobj:D +%</pdftex> + reserveobjnum ~ + \int_gset:Nn \g_@@_backend_object_int +%<*luatex> + { \tex_pdffeedback:D lastobj } +%</luatex> +%<*pdftex> + { \tex_pdflastobj:D } +%</pdftex> + } +\cs_new:Npn \@@_backend_object_ref:n #1 { #1 ~ 0 ~ R } +\cs_new:Npn \@@_backend_object_id:n #1 {#1} +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_object_write:nnn, \@@_backend_object_write:nne} +% \begin{macro}[EXP]{\@@_backend_object_write:nn} +% \begin{macro}[EXP]{\@@_exp_not_i:nn, \@@_exp_not_ii:nn} +% Writing the data needs a little information about the structure of the +% object. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_write:nnn #1#2#3 + { +%<*luatex> + \tex_immediate:D \tex_pdfextension:D obj ~ +%</luatex> +%<*pdftex> + \tex_immediate:D \tex_pdfobj:D +%</pdftex> + useobjnum ~ #1 + \@@_backend_object_write:nn {#2} {#3} + } +\cs_new:Npn \@@_backend_object_write:nn #1#2 + { + \str_case:nn {#1} + { + { array } { { [ ~ \exp_not:n {#2} ~ ] } } + { dict } { { << ~ \exp_not:n {#2} ~ >> } } + { fstream } + { + stream ~ attr ~ { \@@_exp_not_i:nn #2 } ~ + file ~ { \@@_exp_not_ii:nn #2 } + } + { stream } + { + stream ~ attr ~ { \@@_exp_not_i:nn #2 } ~ + { \@@_exp_not_ii:nn #2 } + } + } + } +\cs_generate_variant:Nn \@@_backend_object_write:nnn { nne } +\cs_new:Npn \@@_exp_not_i:nn #1#2 { \exp_not:n {#1} } +\cs_new:Npn \@@_exp_not_ii:nn #1#2 { \exp_not:n {#2} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_object_now:nn, \@@_backend_object_now:ne} +% Much like writing, but direct creation. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_now:nn #1#2 + { +%<*luatex> + \tex_immediate:D \tex_pdfextension:D obj ~ +%</luatex> +%<*pdftex> + \tex_immediate:D \tex_pdfobj:D +%</pdftex> + \@@_backend_object_write:nn {#1} {#2} + } +\cs_generate_variant:Nn \@@_backend_object_now:nn { ne } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_object_last:} +% Much like annotation. +% \begin{macrocode} +\cs_new:Npe \@@_backend_object_last: + { + \exp_not:N \int_value:w +%<*luatex> + \exp_not:N \tex_pdffeedback:D lastobj ~ +%</luatex> +%<*pdftex> + \exp_not:N \tex_pdflastobj:D +%</pdftex> + \c_space_tl 0 ~ R + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_pageobject_ref:n} +% The usual wrapper situation; the three spaces here are essential. +% \begin{macrocode} +\cs_new:Npe \@@_backend_pageobject_ref:n #1 + { + \exp_not:N \int_value:w +%<*luatex> + \exp_not:N \tex_pdffeedback:D pageref +%</luatex> +%<*pdftex> + \exp_not:N \tex_pdfpageref:D +%</pdftex> + \c_space_tl #1 \c_space_tl \c_space_tl \c_space_tl 0 ~ R + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Structure} +% +% \begin{macro}{\@@_backend_compresslevel:n} +% \begin{macro}{\@@_backend_compress_objects:n} +% \begin{macro}{\@@_backend_objcompresslevel:n} +% Simply pass data to the engine. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_compresslevel:n #1 + { + \tex_global:D +%<*luatex> + \tex_pdfvariable:D compresslevel +%</luatex> +%<*pdftex> + \tex_pdfcompresslevel:D +%</pdftex> + \int_value:w \int_eval:n {#1} \scan_stop: + } +\cs_new_protected:Npn \@@_backend_compress_objects:n #1 + { + \bool_if:nTF {#1} + { \@@_backend_objcompresslevel:n { 2 } } + { \@@_backend_objcompresslevel:n { 0 } } + } +\cs_new_protected:Npn \@@_backend_objcompresslevel:n #1 + { + \tex_global:D +%<*luatex> + \tex_pdfvariable:D objcompresslevel +%</luatex> +%<*pdftex> + \tex_pdfobjcompresslevel:D +%</pdftex> + #1 \scan_stop: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\@@_backend_version_major_gset:n, \@@_backend_version_minor_gset:n} +% The availability of the primitive is not universal, so we have to test +% at load time. +% \begin{macrocode} +\cs_new_protected:Npe \@@_backend_version_major_gset:n #1 + { +%<*luatex> + \int_compare:nNnT \tex_luatexversion:D > { 106 } + { + \exp_not:N \tex_global:D \tex_pdfvariable:D majorversion + \exp_not:N \int_eval:n {#1} \scan_stop: + } +%</luatex> +%<*pdftex> + \cs_if_exist:NT \tex_pdfmajorversion:D + { + \exp_not:N \tex_global:D \tex_pdfmajorversion:D + \exp_not:N \int_eval:n {#1} \scan_stop: + } +%</pdftex> + } +\cs_new_protected:Npn \@@_backend_version_minor_gset:n #1 + { + \tex_global:D +%<*luatex> + \tex_pdfvariable:D minorversion +%</luatex> +%<*pdftex> + \tex_pdfminorversion:D +%</pdftex> + \int_eval:n {#1} \scan_stop: + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_version_major:, \@@_backend_version_minor:} +% As above. +% \begin{macrocode} +\cs_new:Npe \@@_backend_version_major: + { +%<*luatex> + \int_compare:nNnTF \tex_luatexversion:D > { 106 } + { \exp_not:N \tex_the:D \tex_pdfvariable:D majorversion } + { 1 } +%</luatex> +%<*pdftex> + \cs_if_exist:NTF \tex_pdfmajorversion:D + { \exp_not:N \tex_the:D \tex_pdfmajorversion:D } + { 1 } +%</pdftex> + } +\cs_new:Npn \@@_backend_version_minor: + { + \tex_the:D +%<*luatex> + \tex_pdfvariable:D minorversion +%</luatex> +%<*pdftex> + \tex_pdfminorversion:D +%</pdftex> + } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Marked content} +% +% \begin{macro}{\@@_backend_bdc:nn} +% \begin{macro}{\@@_backend_emc:} +% Simple wrappers. May need refinement: see +% \url{https://chat.stackexchange.com/transcript/message/49970158#49970158}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_bdc:nn #1#2 + { \__kernel_backend_literal_page:n { /#1 ~ #2 ~ BDC } } +\cs_new_protected:Npn \@@_backend_emc: + { \__kernel_backend_literal_page:n { EMC } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</luatex|pdftex> +% \end{macrocode} +% +% \subsection{\texttt{dvipdfmx} backend} +% +% \begin{macrocode} +%<*dvipdfmx|xetex> +% \end{macrocode} +% +% \begin{macro}{\@@_backend:n, \@@_backend:e} +% A generic function for the backend PDF specials: used where we can. +% \begin{macrocode} +\cs_new_protected:Npe \@@_backend:n #1 + { \__kernel_backend_literal:n { pdf: #1 } } +\cs_generate_variant:Nn \@@_backend:n { e } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Catalogue entries} +% +% \begin{macro}{\@@_backend_catalog_gput:nn, \@@_backend_info_gput:nn} +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_catalog_gput:nn #1#2 + { \@@_backend:n { put ~ @catalog << /#1 ~ #2 >> } } +\cs_new_protected:Npn \@@_backend_info_gput:nn #1#2 + { \@@_backend:n { docinfo << /#1 ~ #2 >> } } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Objects} +% +% \begin{variable}{\g_@@_backend_object_prop} +% For tracking objects to allow finalisation. +% \begin{macrocode} +\prop_new:N \g_@@_backend_object_prop +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_backend_object_new:} +% \begin{macro}[EXP]{\@@_backend_object_ref:n, \@@_backend_object_id:n} +% Objects are tracked at the macro level, but we don't have to do anything +% at this stage. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_new: + { \int_gincr:N \g_@@_backend_object_int } +\cs_new:Npn \@@_backend_object_ref:n #1 { @pdf.obj #1 } +\cs_new_eq:NN \@@_backend_object_id:n \@@_backend_object_ref:n +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_object_write:nnn, \@@_backend_object_write:nne} +% \begin{macro} +% { +% \@@_backend_object_write_array:nn , +% \@@_backend_object_write_dict:nn , +% \@@_backend_object_write_fstream:nn , +% \@@_backend_object_write_stream:nn +% } +% \begin{macro}{\@@_backend_object_write_stream:nnnn} +% This is where we choose the actual type. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_write:nnn #1#2#3 + { + \use:c { @@_backend_object_write_ #2 :nn } + { \@@_backend_object_ref:n {#1} } {#3} + } +\cs_generate_variant:Nn \@@_backend_object_write:nnn { nne } +\cs_new_protected:Npn \@@_backend_object_write_array:nn #1#2 + { + \@@_backend:e + { obj ~ #1 ~ [ ~ \exp_not:n {#2} ~ ] } + } +\cs_new_protected:Npn \@@_backend_object_write_dict:nn #1#2 + { + \@@_backend:e + { obj ~ #1 ~ << ~ \exp_not:n {#2} ~ >> } + } +\cs_new_protected:Npn \@@_backend_object_write_fstream:nn #1#2 + { \@@_backend_object_write_stream:nnnn { f } {#1} #2 } +\cs_new_protected:Npn \@@_backend_object_write_stream:nn #1#2 + { \@@_backend_object_write_stream:nnnn { } {#1} #2 } +\cs_new_protected:Npn \@@_backend_object_write_stream:nnnn #1#2#3#4 + { + \@@_backend:e + { + #1 stream ~ #2 ~ + ( \exp_not:n {#4} ) ~ << \exp_not:n {#3} >> + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_object_now:nn, \@@_backend_object_now:ne} +% No anonymous objects with \texttt{dvipdfmx} so we have to give an +% object name. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_now:nn #1#2 + { + \int_gincr:N \g_@@_backend_object_int + \exp_args:Nne \use:c { @@_backend_object_write_ #1 :nn } + { @pdf.obj \int_use:N \g_@@_backend_object_int } + {#2} + } +\cs_generate_variant:Nn \@@_backend_object_now:nn { ne } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_object_last:} +% \begin{macrocode} +\cs_new:Npn \@@_backend_object_last: + { @pdf.obj \int_use:N \g_@@_backend_object_int } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_pageobject_ref:n} +% Page references are easy in \texttt{dvipdfmx}/\XeTeX{}. +% \begin{macrocode} +\cs_new:Npn \@@_backend_pageobject_ref:n #1 + { @page #1 } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Annotations} +% +% \begin{variable}{\g_@@_backend_annotation_int} +% Needed as objects which are not annotations could be created. +% \begin{macrocode} +\int_new:N \g_@@_backend_annotation_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\@@_backend_annotation:nnnn} +% Simply pass the raw data through, just dealing with evaluation of dimensions. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_annotation:nnnn #1#2#3#4 + { + \int_gincr:N \g_@@_backend_object_int + \int_gset_eq:NN \g_@@_backend_annotation_int \g_@@_backend_object_int + \@@_backend:e + { + ann ~ @pdf.obj \int_use:N \g_@@_backend_object_int \c_space_tl + width ~ \dim_eval:n {#1} ~ + height ~ \dim_eval:n {#2} ~ + depth ~ \dim_eval:n {#3} ~ + << /Type /Annot #4 >> + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_annotation_last:} +% \begin{macrocode} +\cs_new:Npn \@@_backend_annotation_last: + { @pdf.obj \int_use:N \g_@@_backend_annotation_int } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\g_@@_backend_link_int} +% To track annotations which are links. +% \begin{macrocode} +\int_new:N \g_@@_backend_link_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro} +% {\@@_backend_link_begin_goto:nnw, \@@_backend_link_begin_user:nnw} +% \begin{macro}{\@@_backend_link_begin:n} +% \begin{macro}{\@@_backend_link_end:} +% All created using the same internals. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_begin_goto:nnw #1#2 + { \@@_backend_link_begin:n { #1 /Subtype /Link /A << /S /GoTo /D ( #2 ) >> } } +\cs_new_protected:Npn \@@_backend_link_begin_user:nnw #1#2 + { \@@_backend_link_begin:n {#1#2} } +\cs_new_protected:Npe \@@_backend_link_begin:n #1 + { + \exp_not:N \int_gincr:N \exp_not:N \g_@@_backend_link_int + \@@_backend:e + { + bann ~ + @pdf.lnk + \exp_not:N \int_use:N \exp_not:N \g_@@_backend_link_int + \c_space_tl + << + /Type /Annot + #1 + >> + } + } +\cs_new_protected:Npn \@@_backend_link_end: + { \@@_backend:n { eann } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_link_last:} +% Available using the backend mechanism with a suitably-recent +% version. +% \begin{macrocode} +\cs_new:Npn \@@_backend_link_last: + { @pdf.lnk \int_use:N \g_@@_backend_link_int } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_link_margin:n} +% Pass to \texttt{dvipdfmx}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_margin:n #1 + { \__kernel_backend_literal:e { dvipdfmx:config~g~ \dim_eval:n {#1} } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_destination:nn} +% \begin{macro}{\@@_backend_destination:nnnn,\@@_backend_destination_aux:nnnn} +% Here, we need to turn the zoom into a scale. The method for \texttt{FitR} +% is from Alexander Grahn: the idea is to avoid needing to do any calculations +% in \TeX{} by using the backend data for \texttt{@xpos} and \texttt{@ypos}. +% \texttt{/FitR} without rule spec doesn't work, so it falls back to +% \texttt{/Fit} here. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_destination:nn #1#2 + { + \@@_backend:e + { + dest ~ ( \exp_not:n {#1} ) + [ + @thispage + \str_case:nnF {#2} + { + { xyz } { /XYZ ~ @xpos ~ @ypos ~ null } + { fit } { /Fit } + { fitb } { /FitB } + { fitbh } { /FitBH } + { fitbv } { /FitBV ~ @xpos } + { fith } { /FitH ~ @ypos } + { fitv } { /FitV ~ @xpos } + { fitr } { /Fit } + } + { /XYZ ~ @xpos ~ @ypos ~ \fp_eval:n { (#2) / 100 } } + ] + } + } +\cs_new_protected:Npn \@@_backend_destination:nnnn #1#2#3#4 + { + \exp_args:Ne \@@_backend_destination_aux:nnnn + { \dim_eval:n {#2} } {#1} {#3} {#4} + } +\cs_new_protected:Npn \@@_backend_destination_aux:nnnn #1#2#3#4 + { + \vbox_to_zero:n + { + \__kernel_kern:n {#4} + \hbox:n + { + \@@_backend:n { obj ~ @pdf_ #2 _llx ~ @xpos } + \@@_backend:n { obj ~ @pdf_ #2 _lly ~ @ypos } + } + \tex_vss:D + } + \__kernel_kern:n {#1} + \vbox_to_zero:n + { + \__kernel_kern:n { -#3 } + \hbox:n + { + \@@_backend:n + { + dest ~ (#2) + [ + @thispage + /FitR ~ + @pdf_ #2 _llx ~ @pdf_ #2 _lly ~ + @xpos ~ @ypos + ] + } + } + \tex_vss:D + } + \__kernel_kern:n { -#1 } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Structure} +% +% \begin{macro}{\@@_backend_compresslevel:n} +% \begin{macro}{\@@_backend_compress_objects:n} +% Pass data to the backend: these are a one-shot. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_compresslevel:n #1 + { \__kernel_backend_literal:e { dvipdfmx:config~z~ \int_eval:n {#1} } } +\cs_new_protected:Npn \@@_backend_compress_objects:n #1 + { + \bool_if:nF {#1} + { \__kernel_backend_literal:n { dvipdfmx:config~C~0x40 } } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\@@_backend_version_major_gset:n, \@@_backend_version_minor_gset:n} +% We start with the assumption that the default is active. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_version_major_gset:n #1 + { + \cs_gset:Npe \@@_backend_version_major: { \int_eval:n {#1} } + \__kernel_backend_literal:e { pdf:majorversion~ \@@_backend_version_major: } + } +\cs_new_protected:Npn \@@_backend_version_minor_gset:n #1 + { + \cs_gset:Npe \@@_backend_version_minor: { \int_eval:n {#1} } + \__kernel_backend_literal:e { pdf:minorversion~ \@@_backend_version_minor: } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_version_major:, \@@_backend_version_minor:} +% We start with the assumption that the default is active. +% \begin{macrocode} +\cs_new:Npn \@@_backend_version_major: { 1 } +\cs_new:Npn \@@_backend_version_minor: { 5 } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Marked content} +% +% \begin{macro}{\@@_backend_bdc:nn} +% \begin{macro}{\@@_backend_emc:} +% Simple wrappers. May need refinement: see +% \url{https://chat.stackexchange.com/transcript/message/49970158#49970158}. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_bdc:nn #1#2 + { \__kernel_backend_literal_page:n { /#1 ~ #2 ~ BDC } } +\cs_new_protected:Npn \@@_backend_emc: + { \__kernel_backend_literal_page:n { EMC } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</dvipdfmx|xetex> +% \end{macrocode} +% +% \subsection{\texttt{dvisvgm} backend} +% +% \begin{macrocode} +%<*dvisvgm> +% \end{macrocode} +% +% \subsubsection{Annotations} +% +% \begin{macro}{\@@_backend_annotation:nnnn} +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_annotation:nnnn #1#2#3#4 { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_annotation_last:} +% \begin{macrocode} +\cs_new:Npn \@@_backend_annotation_last: { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro} +% {\@@_backend_link_begin_goto:nnw, \@@_backend_link_begin_user:nnw} +% \begin{macro}{\@@_backend_link_begin:nnnw} +% \begin{macro}{\@@_backend_link_end:} +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_begin_goto:nnw #1#2 { } +\cs_new_protected:Npn \@@_backend_link_begin_user:nnw #1#2 { } +\cs_new_protected:Npn \@@_backend_link_begin:nnnw #1#2#3 { } +\cs_new_protected:Npn \@@_backend_link_end: { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_backend_link_last:} +% \begin{macrocode} +\cs_new:Npe \@@_backend_link_last: { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_link_margin:n} +% A simple task: pass the data to the primitive. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_link_margin:n #1 { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_destination:nn} +% \begin{macro}{\@@_backend_destination:nnnn} +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_destination:nn #1#2 { } +\cs_new_protected:Npn \@@_backend_destination:nnnn #1#2#3#4 { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \subsubsection{Catalogue entries} +% +% \begin{macro}{\@@_backend_catalog_gput:nn, \@@_backend_info_gput:nn} +% No-op. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_catalog_gput:nn #1#2 { } +\cs_new_protected:Npn \@@_backend_info_gput:nn #1#2 { } +% \end{macrocode} +% \end{macro} +% +% \subsubsection{Objects} +% +% \begin{macro}{\@@_backend_object_new:} +% \begin{macro}[EXP]{\@@_backend_object_ref:n, \@@_backend_object_id:n} +% \begin{macro}{\@@_backend_object_write:nnn, \@@_backend_object_write:ne} +% \begin{macro}{\@@_backend_object_now:nn, , \@@_backend_object_now:ne} +% \begin{macro}{\@@_backend_object_last:} +% \begin{macro}[EXP]{\@@_backend_pageobject_ref:n} +% All no-ops here. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_object_new: { } +\cs_new:Npn \@@_backend_object_ref:n #1 { } +\cs_new:Npn \@@_backend_object_id:n #1 { } +\cs_new_protected:Npn \@@_backend_object_write:nnn #1#2#3 { } +\cs_new_protected:Npn \@@_backend_object_write:nne #1#2#3 { } +\cs_new_protected:Npn \@@_backend_object_now:nn #1#2 { } +\cs_new_protected:Npn \@@_backend_object_now:ne #1#2 { } +\cs_new:Npn \@@_backend_object_last: { } +\cs_new:Npn \@@_backend_pageobject_ref:n #1 { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \subsubsection{Structure} +% +% \begin{macro}{\@@_backend_compresslevel:n} +% \begin{macro}{\@@_backend_compress_objects:n} +% These are all no-ops. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_compresslevel:n #1 { } +\cs_new_protected:Npn \@@_backend_compress_objects:n #1 { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% {\@@_backend_version_major_gset:n, \@@_backend_version_minor_gset:n} +% Data not available! +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_version_major_gset:n #1 { } +\cs_new_protected:Npn \@@_backend_version_minor_gset:n #1 { } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[EXP]{\@@_backend_version_major:, \@@_backend_version_minor:} +% Data not available! +% \begin{macrocode} +\cs_new:Npn \@@_backend_version_major: { -1 } +\cs_new:Npn \@@_backend_version_minor: { -1 } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_backend_bdc:nn} +% \begin{macro}{\@@_backend_emc:} +% More no-ops. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_bdc:nn #1#2 { } +\cs_new_protected:Npn \@@_backend_emc: { } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</dvisvgm> +% \end{macrocode} +% +% \subsection{PDF Page size (media box)} +% +% For setting the media box, the split between backends is somewhat different +% to other areas, thus we approach this separately. The code here assumes a +% recent \LaTeXe{}: that is ensured at the level above. +% +% \begin{macrocode} +%<*dvipdfmx|dvips> +% \end{macrocode} +% +% \begin{macro}{\@@_backend_pagesize_gset:nn} +% This is done as a backend literal, so we deal with it using the shipout +% hook. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_pagesize_gset:nn #1#2 + { + \__kernel_backend_first_shipout:n + { + \__kernel_backend_literal:e + { +%<*dvipdfmx> + pdf:pagesize ~ + width ~ \dim_eval:n {#1} ~ + height ~ \dim_eval:n {#2} +%</dvipdfmx> +%<*dvips> + papersize = \dim_eval:n {#1} , \dim_eval:n {#2} +%</dvips> + } + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</dvipdfmx|dvips> +% \end{macrocode} +% +% \begin{macrocode} +%<*luatex|pdftex|xetex> +% \end{macrocode} +% +% \begin{macro}{\@@_backend_pagesize_gset:nn} +% Pass to the primitives. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_pagesize_gset:nn #1#2 + { + \dim_gset:Nn \tex_pagewidth:D {#1} + \dim_gset:Nn \tex_pageheight:D {#2} + } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</luatex|pdftex|xetex> +% \end{macrocode} +% +% \begin{macrocode} +%<*dvisvgm> +% \end{macrocode} +% +% \begin{macro}{\@@_backend_pagesize_gset:nn} +% A no-op. +% \begin{macrocode} +\cs_new_protected:Npn \@@_backend_pagesize_gset:nn #1#2 { } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</dvisvgm> +% \end{macrocode} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex |