summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx1934
1 files changed, 0 insertions, 1934 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx
deleted file mode 100644
index 62a3bea1119..00000000000
--- a/Master/texmf-dist/source/latex/l3kernel/l3drivers-pdf.dtx
+++ /dev/null
@@ -1,1934 +0,0 @@
-% \iffalse meta-comment
-%
-%% File: l3drivers-pdf.dtx
-%
-% Copyright (C) 2011-2019 The LaTeX3 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 "l3kernel 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 \textsf{l3drivers-pdf} package\\ Driver PDF features^^A
-% }
-%
-% \author{^^A
-% The \LaTeX3 Project\thanks
-% {^^A
-% E-mail:
-% \href{mailto:latex-team@latex-project.org}
-% {latex-team@latex-project.org}^^A
-% }^^A
-% }
-%
-% \date{Released 2019-05-28}
-%
-% \maketitle
-%
-% \begin{documentation}
-%
-% \end{documentation}
-%
-% \begin{implementation}
-%
-% \section{\pkg{l3drivers-pdf} Implementation}
-%
-% \begin{macrocode}
-%<*initex|package>
-%<@@=driver>
-% \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 driver level but which
-% are common to all drivers.
-%
-% \subsection{\texttt{dvips} driver}
-%
-% \begin{macrocode}
-%<*dvips>
-% \end{macrocode}
-%
-% \begin{macro}{\@@_pdfmark:n, \@@_pdfmark:x}
-% Used often enough it should be a separate function.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_pdfmark:n #1
- { \@@_postscript:n { mark #1 ~ pdfmark } }
-\cs_generate_variant:Nn \@@_pdfmark:n { x }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Catalogue entries}
-%
-% \begin{macro}{\driver_pdf_catalog_gput:nn, \driver_pdf_info_gput:nn}
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_catalog_gput:nn #1#2
- { \@@_pdfmark:n { { Catalog } << /#1 ~ #2 >> /PUT } }
-\cs_new_protected:Npn \driver_pdf_info_gput:nn #1#2
- { \@@_pdfmark:n { /#1 ~ #2 /DOCINFO } }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Objects}
-%
-% \begin{variable}{\g_@@_pdf_object_int, \g_@@_pdf_object_prop}
-% For tracking objects to allow finalisation.
-% \begin{macrocode}
-\int_new:N \g_@@_pdf_object_int
-\prop_new:N \g_@@_pdf_object_prop
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\driver_pdf_object_new:nn}
-% \begin{macro}[EXP]{\driver_pdf_object_ref:n}
-% Tracking objects is similar to \texttt{dvipdfmx}.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_object_new:nn #1#2
- {
- \int_gincr:N \g_@@_pdf_object_int
- \int_const:cn
- { c_@@_pdf_object_ \tl_to_str:n {#1} _int }
- { \g_@@_pdf_object_int }
- \prop_gput:Nnn \g_@@_pdf_object_prop {#1} {#2}
- }
-\cs_new:Npn \driver_pdf_object_ref:n #1
- { { driver.obj \int_use:c { c_@@_pdf_object_ \tl_to_str:n {#1} _int } } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_object_write:nn}
-% \begin{macro}
-% {
-% \@@_pdf_object_write_array:nn ,
-% \@@_pdf_object_write_dict:nn ,
-% \@@_pdf_object_write_stream:nn
-% }
-% \begin{macro}{\@@_pdf_object_write_stream:nnn}
-% This is where we choose the actual type: some work to get things
-% right.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_object_write:nn #1#2
- {
- \@@_pdfmark:x
- {
- /_objdef ~ \driver_pdf_object_ref:n {#1}
- /type
- \str_case_e:nn
- { \prop_item:Nn \g_@@_pdf_object_prop {#1} }
- {
- { array } { /array }
- { dict } { /dict }
- { fstream } { /stream }
- { stream } { /stream }
- }
- /OBJ
- }
- \use:c
- { @@_pdf_object_write_ \prop_item:Nn \g_@@_pdf_object_prop {#1} :nn }
- {#1} {#2}
- }
-\cs_new_protected:Npn \@@_pdf_object_write_array:nn #1#2
- {
- \@@_pdfmark:x
- {
- \driver_pdf_object_ref:n {#1}
- [ ~ \exp_not:n {#2} ~ ] ~ /PUTINTERVAL
- }
- }
-\cs_new_protected:Npn \@@_pdf_object_write_dict:nn #1#2
- {
- \@@_pdfmark:x
- {
- \driver_pdf_object_ref:n {#1}
- << \exp_not:n {#2} >> /PUT
- }
- }
-\cs_new_protected:Npn \@@_pdf_object_write_stream:nn #1#2
- {
- \exp_args:Nx
- \@@_pdf_object_write_stream:nnn
- { \driver_pdf_object_ref:n {#1} }
- #2
- }
-\cs_new_protected:Npn \@@_pdf_object_write_stream:nnn #1#2#3
- {
- \@@_postscript:n
- {
- [nobreak]
- mark ~ #1 ~ ( #3 ) /PUT ~ pdfmark ~
- mark ~ #1 ~ << #2 >> /PUT ~ pdfmark
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \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{macro}{driver.globaldict}
-% A small global dictionary for driver use.
-% \begin{macrocode}
-\@@_postscript_header:n
- {
- true ~ setglobal ~
- /driver.globaldict ~ 4 ~ dict ~ def ~
- false ~ setglobal
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% driver.cvs ,
-% driver.dvi.pt ,
-% driver.pt.dvi ,
-% driver.rect.ht
-% }
-% Small utilities for PostScript manipulations. Conversion to DVI dimensions
-% is done here to allow for |Resolution|. The total height of a rectangle
-% (an array) needs a little maths, in contrast to simply extracting a value.
-% \begin{macrocode}
-\@@_postscript_header:n
- {
- /driver.cvs { 65534 ~ string ~ cvs } def
- /driver.dvi.pt { 72.27 ~ mul ~ Resolution ~ div } def
- /driver.pt.dvi { 72.27 ~ div ~ Resolution ~ mul } def
- /driver.rect.ht { dup ~ 1 ~ get ~ neg ~ exch ~ 3 ~ get ~ add } def
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{driver.linkmargin, driver.linkdp.pad, driver.linkht.pad}
-% Settings which are defined up-front in |SDict|.
-% \begin{macrocode}
-\@@_postscript_header:n
- {
- /driver.linkmargin { 1 ~ driver.pt.dvi } def
- /driver.linkdp.pad { 0 } def
- /driver.linkht.pad { 0 } def
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% driver.rect ,
-% driver.save.ll ,
-% driver.save.ur ,
-% driver.save.linkll ,
-% driver.save.linkur ,
-% driver.llx ,
-% driver.lly ,
-% driver.urx ,
-% driver.ury
-% }
-% Functions for marking the limits of an annotation/link, plus drawing the
-% border. We separate links for generic annotations to support adding a
-% margin and setting a minimal size.
-% \begin{macrocode}
-\@@_postscript_header:n
- {
- /driver.rect
- { /Rect [ driver.llx ~ driver.lly ~ driver.urx ~ driver.ury ] } def
- /driver.save.ll
- {
- currentpoint
- /driver.lly ~ exch ~ def
- /driver.llx ~ exch ~ def
- }
- def
- /driver.save.ur
- {
- currentpoint
- /driver.ury ~ exch ~ def
- /driver.urx ~ exch ~ def
- }
- def
- /driver.save.linkll
- {
- currentpoint ~
- driver.linkmargin ~ add ~
- driver.linkdp.pad ~ add
- /driver.lly ~ exch ~ def ~
- driver.linkmargin ~ sub
- /driver.llx ~ exch ~ def
- }
- def
- /driver.save.linkur
- {
- currentpoint ~
- driver.linkmargin ~ sub ~
- driver.linkht.pad ~ sub
- /driver.ury ~ exch ~ def ~
- driver.linkmargin ~ add
- /driver.urx ~ exch ~ def
- }
- def
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% driver.dest.anchor ,
-% driver.dest.x ,
-% driver.dest.y ,
-% driver.dest.point ,
-% driver.dest2device ,
-% driver.dev.x ,
-% driver.dev.y ,
-% driver.tmpa ,
-% driver.tmpb ,
-% driver.tmpc ,
-% driver.tmpd
-% }
-% For finding the anchor point of a destination link. We make the use case
-% a separate function as it comes up a lot, and as this makes it easier to
-% adjust if we need additional effects. We also need a more complex approach
-% to convert a co-ordinate pair correctly when defining a rectangle: this
-% can otherwise be out when using a landscape page. (Thanks to Alexander
-% Grahn for the approach here.)
-% \begin{macrocode}
-\@@_postscript_header:n
- {
- /driver.dest.anchor
- {
- currentpoint ~ exch ~
- driver.dvi.pt ~ 72 ~ add ~
- /driver.dest.x ~ exch ~ def ~
- driver.dvi.pt ~
- vsize ~ 72 ~ sub ~ exch ~ sub ~
- /driver.dest.y ~ exch ~ def
- }
- def
- /driver.dest.point
- { driver.dest.x ~ driver.dest.y } def
- /driver.dest2device
- {
- /driver.dest.y ~ exch ~ def
- /driver.dest.x ~ exch ~ def ~
- matrix ~ currentmatrix ~
- matrix ~ defaultmatrix ~
- matrix ~ invertmatrix ~
- matrix ~ concatmatrix ~
- cvx ~ exec
- /driver.dev.y ~ exch ~ def
- /driver.dev.x ~ exch ~ def
- /driver.tmpd ~ exch ~ def
- /driver.tmpc ~ exch ~ def
- /driver.tmpb ~ exch ~ def
- /driver.tmpa ~ exch ~ def ~
- driver.dest.x ~ driver.tmpa ~ mul ~
- driver.dest.y ~ driver.tmpc ~ mul ~ add ~
- driver.dev.x ~ add ~
- driver.dest.x ~ driver.tmpb ~ mul ~
- driver.dest.y ~ driver.tmpd ~ mul ~ add ~
- driver.dev.y ~ add
- }
- def
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% driver.bordertracking ,
-% driver.bordertracking.begin ,
-% driver.bordertracking.end ,
-% driver.leftboundary ,
-% driver.rightboundary ,
-% driver.brokenlink.rect ,
-% driver.brokenlink.skip ,
-% driver.brokenlink.dict ,
-% driver.bordertracking.endpage ,
-% driver.bordertracking.continue ,
-% driver.originx ,
-% driver.originy
-% }
-% To know where a breakable link can go, we need to track the boundary
-% rectangle. That can be done by hooking into |a| and |x| operations:
-% those names have to be retained. The boundary is stored at the end of
-% the operation. Special effort is needed at the start and end of pages
-% (or rather galleys), such that everything works properly.
-% \begin{macrocode}
-\@@_postscript_header:n
- {
- /driver.bordertracking ~ false ~ def
- /driver.bordertracking.begin
- {
- SDict ~ /driver.bordertracking ~ true ~ put ~
- SDict ~ /driver.leftboundary ~ undef ~
- SDict ~ /driver.rightboundary ~ undef ~
- /a ~ where
- {
- /a
- {
- currentpoint ~ pop ~
- SDict /driver.rightboundary ~ known ~ dup
- {
- SDict /driver.rightboundary ~ get ~ 2 ~ index ~ lt
- { not }
- if
- }
- if
- { pop }
- { SDict ~ exch /driver.rightboundary ~ exch ~ put }
- ifelse ~
- moveto ~
- currentpoint ~ pop ~
- SDict /driver.leftboundary ~ known ~ dup
- {
- SDict /driver.leftboundary ~ get ~ 2 ~ index ~ gt
- { not }
- if
- }
- if
- { pop }
- { SDict ~ exch /driver.leftboundary ~ exch ~ put }
- ifelse
- }
- put
- }
- if
- }
- def
- /driver.bordertracking.end
- {
- /a ~ where { /a { moveto } put } if
- /x ~ where { /x { 0 ~ exch ~ rmoveto } put } if ~
- SDict /driver.leftboundary ~ known
- { driver.outerbox ~ 0 ~ driver.leftboundary ~ put }
- if ~
- SDict /driver.rightboundary ~ known
- { driver.outerbox ~ 2 ~ driver.rightboundary ~ put }
- if ~
- SDict /driver.bordertracking ~ false ~ put
- }
- def
- /driver.bordertracking.endpage
- {
- driver.bordertracking
- {
- driver.bordertracking.end ~
- true ~ setglobal ~
- driver.globaldict
- /driver.brokenlink.rect [ driver.outerbox ~ aload ~ pop ] put ~
- driver.globaldict
- /driver.brokenlink.skip ~ driver.baselineskip ~ put ~
- driver.globaldict
- /driver.brokenlink.dict ~
- driver.link.dict ~ driver.cvs ~ put ~
- false ~ setglobal ~
- mark ~ driver.link.dict ~ cvx ~ exec ~ /Rect
- [
- driver.llx ~
- driver.lly ~
- driver.outerbox ~ 2 ~ get ~ driver.linkmargin ~ add ~
- currentpoint ~ exch ~ pop ~
- driver.outerbox ~ driver.rect.ht ~ sub ~ driver.linkmargin ~ sub
- ]
- /ANN ~ driver.pdfmark
- }
- if
- }
- def
- /driver.bordertracking.continue
- {
- /driver.link.dict ~ driver.globaldict
- /driver.brokenlink.dict ~ get ~ def
- /driver.outerbox ~ driver.globaldict
- /driver.brokenlink.rect ~ get ~ def
- /driver.baselineskip ~ driver.globaldict
- /driver.brokenlink.skip ~ get ~ def ~
- driver.globaldict ~ dup ~ dup
- /driver.brokenlink.dict ~ undef
- /driver.brokenlink.skip ~ undef
- /driver.brokenlink.rect ~ undef ~
- currentpoint
- /driver.originy ~ exch ~ def
- /driver.originx ~ exch ~ def
- /a ~ where
- {
- /a
- {
- moveto ~
- SDict ~
- begin ~
- currentpoint ~ driver.originy ~ ne ~ exch ~
- driver.originx ~ ne ~ or
- {
- driver.save.linkll
- /driver.lly ~
- driver.lly ~ driver.outerbox ~ 1 ~ get ~ sub ~ def ~
- driver.bordertracking.begin
- }
- if ~
- end
- }
- put
- }
- if
- /x ~ where
- {
- /x
- {
- 0 ~ exch ~ rmoveto ~
- SDict~
- begin ~
- currentpoint ~
- driver.originy ~ ne ~ exch ~ driver.originx ~ ne ~ or
- {
- driver.save.linkll
- /driver.lly ~
- driver.lly ~ driver.outerbox ~ 1 ~ get ~ sub ~ def ~
- driver.bordertracking.begin
- }
- if ~
- end
- }
- put
- }
- if
- }
- def
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% driver.breaklink ,
-% driver.breaklink.write ,
-% driver.count ,
-% driver.currentrect
-% }
-% Dealing with link breaking itself has multiple stage. The first step is to
-% find the |Rect| entry in the dictionary, looping over key--value pairs.
-% The first line is handled first, adjusting the rectangle to stay inside the
-% text area. The second phase is a loop over the height of the bulk of the
-% link area, done on the basis of a number of baselines. Finally, the end of
-% the link area is tidied up, again from the boundary of the text area.
-% \begin{macrocode}
-\@@_postscript_header:n
- {
- /driver.breaklink
- {
- pop ~
- counttomark ~ 2 ~ mod ~ 0 ~ eq
- {
- counttomark /driver.count ~ exch ~ def
- {
- driver.count ~ 0 ~ eq { exit } if ~
- counttomark ~ 2 ~ roll ~
- 1 ~ index ~ /Rect ~ eq
- {
- dup ~ 4 ~ array ~ copy ~
- dup ~ dup ~
- 1 ~ get ~
- driver.outerbox ~ driver.rect.ht ~
- driver.linkmargin ~ 2 ~ mul ~ add ~ sub ~
- 3 ~ exch ~ put ~
- dup ~
- driver.outerbox ~ 2 ~ get ~
- driver.linkmargin ~ add ~
- 2 ~ exch ~ put ~
- dup ~ dup ~
- 3 ~ get ~
- driver.outerbox ~ driver.rect.ht ~
- driver.linkmargin ~ 2 ~ mul ~ add ~ add ~
- 1 ~ exch ~ put
- /driver.currentrect ~ exch ~ def ~
- driver.breaklink.write
- {
- driver.currentrect ~
- dup ~
- driver.outerbox ~ 0 ~ get ~
- driver.linkmargin ~ sub ~
- 0 ~ exch ~ put ~
- dup ~
- driver.outerbox ~ 2 ~ get ~
- driver.linkmargin ~ add ~
- 2 ~ exch ~ put ~
- dup ~ dup ~
- 1 ~ get ~
- driver.baselineskip ~ add ~
- 1 ~ exch ~ put ~
- dup ~ dup ~
- 3 ~ get ~
- driver.baselineskip ~ add ~
- 3 ~ exch ~ put ~
- /driver.currentrect ~ exch ~ def ~
- driver.breaklink.write
- }
- 1 ~ index ~ 3 ~ get ~
- driver.linkmargin ~ 2 ~ mul ~ add ~
- driver.outerbox ~ driver.rect.ht ~ add ~
- 2 ~ index ~ 1 ~ get ~ sub ~
- driver.baselineskip ~ div ~ round ~ cvi ~ 1 ~ sub ~
- exch ~
- repeat ~
- driver.currentrect ~
- dup ~
- driver.outerbox ~ 0 ~ get ~
- driver.linkmargin ~ sub ~
- 0 ~ exch ~ put ~
- dup ~ dup ~
- 1 ~ get ~
- driver.baselineskip ~ add ~
- 1 ~ exch ~ put ~
- dup ~ dup ~
- 3 ~ get ~
- driver.baselineskip ~ add ~
- 3 ~ exch ~ put ~
- dup ~ 2 ~ index ~ 2 ~ get ~ 2 ~ exch ~ put
- /driver.currentrect ~ exch ~ def ~
- driver.breaklink.write ~
- SDict /driver.pdfmark.good ~ false ~ put ~
- exit
- }
- { driver.count ~ 2 ~ sub /driver.count ~ exch ~ def }
- ifelse
- }
- loop
- }
- if
- /ANN
- }
- def
- /driver.breaklink.write
- {
- counttomark ~ 1 ~ sub ~
- index /_objdef ~ eq
- {
- counttomark ~ -2 ~ roll ~
- dup ~ wcheck ~
- {
- readonly ~
- counttomark ~ 2 ~ roll
- }
- { pop ~ pop }
- ifelse
- }
- if ~
- counttomark ~ 1 ~ add ~ copy ~
- pop ~ driver.currentrect
- /ANN ~ pdfmark
- }
- def
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {
-% driver.pdfmark ,
-% driver.pdfmark.good ,
-% driver.outerbox ,
-% driver.baselineskip ,
-% driver.pdfmark.dict
-% }
-% The business end of breaking links starts by hooking into |pdfmarks|.
-% Unlike \pkg{hypdvips}, we avoid altering any links we have not created
-% by using a copy of the core |pdfmarks| function. Only mark types which
-% are known are altered. At present, this is purely |ANN| marks, which are
-% measured relative to the size of the baseline skip. If they are
-% more than one apparent line high, breaking is applied.
-% \begin{macrocode}
-\@@_postscript_header:n
- {
- /driver.pdfmark
- {
- SDict /driver.pdfmark.good ~ true ~ put ~
- dup /ANN ~ eq
- {
- driver.pdfmark.store ~
- driver.pdfmark.dict ~
- begin ~
- Subtype /Link ~ eq ~
- currentdict /Rect ~ known ~ and ~
- SDict /driver.outerbox ~ known ~ and ~
- SDict /driver.baselineskip ~ known ~ and ~
- {
- Rect ~ 3 ~ get ~
- driver.linkmargin ~ 2 ~ mul ~ add ~
- driver.outerbox ~ driver.rect.ht ~ add ~
- Rect ~ 1 ~ get ~ sub ~
- driver.baselineskip ~ div ~ round ~ cvi ~ 0 ~ gt
- { driver.breaklink }
- if
- }
- if ~
- end ~
- SDict /driver.outerbox ~ undef ~
- SDict /driver.baselineskip ~ undef ~
- currentdict /driver.pdfmark.dict ~ undef ~
- }
- if ~
- driver.pdfmark.good
- { pdfmark }
- { cleartomark }
- ifelse
- }
- def
- /driver.pdfmark.store
- {
- /driver.pdfmark.dict ~ 65534 ~ dict ~ def ~
- counttomark ~ 1 ~ add ~ copy ~
- pop
- {
- dup ~ mark ~ eq
- {
- pop ~
- exit
- }
- {
- driver.pdfmark.dict ~
- begin ~ def ~ end
- }
- ifelse
- }
- loop
- }
- def
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{variable}{\l_@@_pdf_content_box}
-% The content of an annotation.
-% \begin{macrocode}
-\box_new:N \l_@@_pdf_content_box
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_pdf_model_box}
-% For creating model sizing for links.
-% \begin{macrocode}
-\box_new:N \l_@@_pdf_model_box
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\g_@@_pdf_annotation_int}
-% Needed as objects which are not annotations could be created.
-% \begin{macrocode}
-\int_new:N \g_@@_pdf_annotation_int
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\driver_pdf_annotation:nnnn, \@@_pdf_annotation:nnnn}
-% \begin{macro}{driver.llx, driver.lly, driver.urx, driver.ury}
-% 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. There is a split into two parts here to allow an easy way of
-% applying the Adobe Reader fix.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_annotation:nnnn #1#2#3#4
- {
- \@@_pdf_annotation:nnnn {#1} {#2} {#3} {#4}
- \int_gincr:N \g_@@_pdf_object_int
- \int_gset_eq:NN \g_@@_pdf_annotation_int \g_@@_pdf_object_int
- \@@_pdfmark:x
- {
-
- /_objdef { driver.obj \int_use:N \g_@@_pdf_object_int }
- driver.rect ~
- #4 ~
- /ANN
- }
- }
-\cs_new_protected:Npn \@@_pdf_annotation:nnnn #1#2#3#4
- {
- \box_move_down:nn {#3}
- { \hbox:n { \@@_postscript:n { driver.save.ll } } }
- \hbox:n {#4}
- \box_move_up:nn {#2}
- {
- \hbox:n
- {
- \tex_kern:D \dim_eval:n {#1} \scan_stop:
- \@@_postscript:n { driver.save.ur }
- }
- }
- \int_gincr:N \g_@@_pdf_object_int
- \int_gset_eq:NN \g_@@_pdf_annotation_int \g_@@_pdf_object_int
- \@@_pdfmark:x
- {
- /_objdef { driver.obj \int_use:N \g_@@_pdf_object_int }
- driver.rect
- /ANN
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\driver_pdf_annotation_last:}
-% Provide the last annotation we created: could get tricky of course if
-% other packages are loaded.
-% \begin{macrocode}
-\cs_new:Npn \driver_pdf_annotation_last:
- { { driver.obj \int_use:N \g_@@_pdf_annotation_int } }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{variable}{\g_@@_pdf_link_int}
-% To track annotations which are links.
-% \begin{macrocode}
-\int_new:N \g_@@_pdf_link_int
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\g_@@_pdf_link_dict_tl}
-% To pass information to the end-of-link function.
-% \begin{macrocode}
-\tl_new:N \g_@@_pdf_link_dict_tl
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\g_@@_pdf_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_@@_pdf_link_sf_int
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\g_@@_pdf_link_math_bool}
-% Needed to save/restore math mode.
-% \begin{macrocode}
-\bool_new:N \g_@@_pdf_link_math_bool
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\g_@@_pdf_link_bool}
-% Track link formation: we cannot nest at all.
-% \begin{macrocode}
-\bool_new:N \g_@@_pdf_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}{\driver_pdf_link_begin_goto:nnw, \driver_pdf_link_begin_user:nnw}
-% \begin{macro}{\@@_pdf_link:nw, \@@_pdf_link_aux:nw}
-% \begin{macro}{\driver_pdf_link_end:, \@@_pdf_link_end:}
-% \begin{macro}{\@@_pdf_link_minima:}
-% \begin{macro}{\@@_pdf_link_outerbox:n}
-% \begin{macro}{\@@_pdf_link_sf_save:, \@@_pdf_link_sf_restore:}
-% \begin{macro}
-% {
-% driver.linkdp.pad ,
-% driver.linkht.pad ,
-% driver.llx, driver.lly ,
-% driver.ury, driver.ury ,
-% driver.link.dict ,
-% driver.outerbox ,
-% driver.baselineskip
-% }
-% 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{}.
-%
-% 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 format mode are still to re-examine.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_link_begin_goto:nnw #1#2
- { \@@_pdf_link_begin:nw { #1 /Subtype /Link /A << /S /GoTo /D ( #2 ) >> } }
-\cs_new_protected:Npn \driver_pdf_link_begin_user:nnw #1#2
- { \@@_pdf_link_begin:nw {#1#2} }
-\cs_new_protected:Npn \@@_pdf_link_begin:nw #1
- {
- \bool_if:NF \g_@@_pdf_link_bool
- { \@@_pdf_link_begin_aux:nw {#1} }
- }
-\cs_new_protected:Npn \@@_pdf_link_begin_aux:nw #1
- {
- \bool_gset_true:N \g_@@_pdf_link_bool
- \@@_postscript:n
- { /driver.link.dict ( #1 ) def }
- \tl_gset:Nn \g_@@_pdf_link_dict_tl {#1}
- \@@_pdf_link_sf_save:
- \mode_if_math:TF
- { \bool_gset_true:N \g_@@_pdf_link_math_bool }
- { \bool_gset_false:N \g_@@_pdf_link_math_bool }
- \hbox_set:Nw \l_@@_pdf_content_box
- \@@_pdf_link_sf_restore:
- \bool_if:NT \g_@@_pdf_link_math_bool
- { \c_math_toggle_token }
- }
-\cs_new_protected:Npn \driver_pdf_link_end:
- {
- \bool_if:NT \g_@@_pdf_link_bool
- { \@@_pdf_link_end: }
- }
-\cs_new_protected:Npn \@@_pdf_link_end:
- {
- \bool_if:NT \g_@@_pdf_link_math_bool
- { \c_math_toggle_token }
- \@@_pdf_link_sf_save:
- \hbox_set_end:
- \@@_pdf_link_minima:
- \hbox_set:Nn \l_@@_pdf_model_box { Gg }
- \exp_args:Nx \@@_driver_link_outerbox:n
- {
-%<*initex>
- \l_galley_total_left_margin_dim
-%</initex>
-%<*package>
- \int_if_odd:nTF { \value { page } }
- { \oddsidemargin }
- { \evensidemargin }
-%</package>
- }
- \box_move_down:nn { \box_dp:N \l_@@_pdf_content_box }
- { \hbox:n { \@@_postscript:n { driver.save.linkll } } }
- \@@_breaklink_postscript:n { driver.bordertracking.begin }
- \@@_breaklink_usebox:N \l_@@_pdf_content_box
- \@@_breaklink_postscript:n { driver.bordertracking.end }
- \box_move_up:nn { \box_ht:N \l_@@_pdf_content_box }
- {
- \hbox:n
- { \@@_postscript:n { driver.save.linkur } }
- }
- \int_gincr:N \g_@@_pdf_object_int
- \int_gset_eq:NN \g_@@_pdf_link_int \g_@@_pdf_object_int
- \@@_postscript:x
- {
- mark
- /_objdef { driver.obj \int_use:N \g_@@_pdf_link_int }
- \g_@@_pdf_link_dict_tl \c_space_tl
- driver.rect
- /ANN ~ \l_@@_breaklink_pdfmark_tl
- }
- \@@_pdf_link_sf_restore:
- \bool_gset_false:N \g_@@_pdf_link_bool
- }
-\cs_new_protected:Npn \@@_pdf_link_minima:
- {
- \hbox_set:Nn \l_@@_pdf_model_box { Gg }
- \@@_postscript:x
- {
- /driver.linkdp.pad ~
- \dim_to_decimal:n
- {
- \dim_max:nn
- {
- \box_dp:N \l_@@_pdf_model_box
- - \box_dp:N \l_@@_pdf_content_box
- }
- { 0pt }
- } ~
- driver.pt.dvi ~ def
- /driver.linkht.pad ~
- \dim_to_decimal:n
- {
- \dim_max:nn
- {
- \box_ht:N \l_@@_pdf_model_box
- - \box_ht:N \l_@@_pdf_content_box
- }
- { 0pt }
- } ~
- driver.pt.dvi ~ def
- }
- }
-\cs_new_protected:Npn \@@_driver_link_outerbox:n #1
- {
- \@@_postscript:x
- {
- /driver.outerbox
- [
- \dim_to_decimal:n {#1} ~
- \dim_to_decimal:n { -\box_dp:N \l_@@_pdf_model_box } ~
-%<*initex>
- \dim_to_decimal:n { #1 + \l_galley_text_width_dim } ~
-%</initex>
-%<*package>
- \dim_to_decimal:n { #1 + \textwidth } ~
-%</package>
- \dim_to_decimal:n { \box_ht:N \l_@@_pdf_model_box }
- ]
- [ exch { driver.pt.dvi } forall ] def
- /driver.baselineskip ~
- \dim_to_decimal:n { \tex_baselineskip:D } ~ dup ~ 0 ~ gt
- { driver.pt.dvi ~ def }
- { pop ~ pop }
- ifelse
- }
- }
-\cs_new_protected:Npn \@@_pdf_link_sf_save:
- {
- \int_gset:Nn \g_@@_pdf_link_sf_int
- {
- \mode_if_horizontal:TF
- { \tex_spacefactor:D }
- { 0 }
- }
- }
-\cs_new_protected:Npn \@@_pdf_link_sf_restore:
- {
- \mode_if_horizontal:T
- {
- \int_compare:nNnT \g_@@_pdf_link_sf_int > { 0 }
- { \int_set_eq:NN \tex_spacefactor:D \g_@@_pdf_link_sf_int }
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\@makecol@hook}
-% 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}
-%<*package>
-\use_none:n
- {
- \cs_if_exist:NT \@makecol@hook
- {
- \tl_put_right:Nn \@makecol@hook
- {
- \box_if_empty:NF \@cclv
- {
- \vbox_set:Nn \@cclv
- {
- \@@_postscript:n
- {
- driver.globaldict /driver.brokenlink.rect ~ known
- { driver.bordertracking.continue }
- if
- }
- \vbox_unpack_drop:N \@cclv
- \@@_postscript:n
- { driver.bordertracking.endpage }
- }
- }
- }
- \tl_set:Nn \l_@@_breaklink_pdfmark_tl { driver.pdfmark }
- \cs_set_eq:NN \@@_breaklink_postscript:n \@@_postscript:n
- \cs_set_eq:NN \@@_breaklink_usebox:N \hbox_unpack:N
- }
- }
-%</package>
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_link_last:}
-% The same as annotations, but with a custom integer.
-% \begin{macrocode}
-\cs_new:Npn \driver_pdf_link_last:
- { { driver.obj \int_use:N \g_@@_pdf_link_int } }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_link_margin:n}
-% Convert to big points and pass to PostScript.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_link_margin:n #1
- {
- \@@_postscript:x
- {
- /driver.linkmargin { \dim_to_decimal:n {#1} ~ driver.pt.dvi } def
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_destination:nn, \driver_pdf_destination_rectangle:nn}
-% 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.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_destination:nn #1#2
- {
- \@@_postscript:n { driver.dest.anchor }
- \@@_pdfmark:x
- {
- /View
- [
- \str_case:nnF {#2}
- {
- { xyz } { /XYZ ~ driver.dest.point ~ null }
- { fit } { /Fit }
- { fitb } { /FitB }
- { fitbh } { /FitBH ~ driver.dest.y }
- { fitbv } { /FitBV ~ driver.dest.x }
- { fith } { /FitH ~ driver.dest.y }
- { fitv } { /FitV ~ driver.dest.x }
- }
- {
- /XYZ ~ driver.dest.point ~ \fp_eval:n { (#2) / 100 }
- }
- ]
- /Dest ( \exp_not:n {#1} ) cvn
- /DEST
- }
- }
-\cs_new_protected:Npn \driver_pdf_destination_rectangle:nn #1#2
- {
- \group_begin:
- \hbox_set:Nn \l_@@_internal_box {#2}
- \box_move_down:nn
- { \box_dp:N \l_@@_internal_box }
- { \hbox:n { \@@_postscript:n { driver.save.ll } } }
- \box_use:N \l_@@_internal_box
- \box_move_up:nn
- { \box_ht:N \l_@@_internal_box }
- { \hbox:n { \@@_postscript:n { driver.save.ur } } }
- \@@_pdfmark:n
- {
- /View
- [
- /FitR ~
- driver.llx ~ driver.lly ~ driver.dest2device ~
- driver.urx ~ driver.ury ~ driver.dest2device
- ]
- /Dest ( #1 ) cvn
- /DEST
- }
- \group_end:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Structure}
-%
-% \begin{macro}{\driver_pdf_compresslevel:n}
-% \begin{macro}{\driver_pdf_compress_objects:n}
-% These are all no-ops.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_compresslevel:n #1 { }
-\cs_new_protected:Npn \driver_pdf_compress_objects:n #1 { }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n}
-% Data not available!
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_version_major_gset:n #1 { }
-\cs_new_protected:Npn \driver_pdf_version_minor_gset:n #1 { }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\driver_pdf_version_major:, \driver_pdf_version_minor:}
-% Data not available!
-% \begin{macrocode}
-\cs_new:Npn \driver_pdf_version_major: { -1 }
-\cs_new:Npn \driver_pdf_version_minor: { -1 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macrocode}
-%</dvips>
-% \end{macrocode}
-%
-% \subsection{\texttt{pdfmode} driver}
-%
-% \begin{macrocode}
-%<*pdfmode>
-% \end{macrocode}
-%
-% \subsubsection{Annotations}
-%
-% \begin{macro}{\driver_pdf_annotation:nnnn}
-% Simply pass the raw data through, just dealing with evaluation of dimensions.
-% \begin{macrocode}
-\cs_new_protected:Npx \driver_pdf_annotation:nnnn #1#2#3#4
- {
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D annot ~ }
- { \tex_pdfannot:D }
- width ~ \exp_not:N \dim_eval:n {#1} ~
- height ~ \exp_not:N \dim_eval:n {#2} ~
- depth ~ \exp_not:N \dim_eval:n {#3} ~
- {#4}
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\driver_pdf_annotation_last:}
-% A tiny amount of extra data gets added here.
-% \begin{macrocode}
-\cs_new:Npx \driver_pdf_annotation_last:
- {
- \exp_not:N \tex_the:D
- \cs_if_exist:NTF \tex_pdffeedback:D
- { \exp_not:N \tex_pdffeedback:D annot ~ }
- { \exp_not:N \tex_pdflastannot:D }
- 0 ~ R
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {\driver_pdf_link_begin_goto:nnw, \driver_pdf_link_begin_user:nnw}
-% \begin{macro}{\@@_pdf_link_begin:nnnw}
-% \begin{macro}{\driver_pdf_link_end:}
-% Links are all created using the same internals.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_link_begin_goto:nnw #1#2
- { \@@_pdf_link_begin:nnnw {#1} { goto~name } {#2} }
-\cs_new_protected:Npn \driver_pdf_link_begin_user:nnw #1#2
- { \@@_pdf_link_begin:nnnw {#1} { user } {#2} }
-\cs_new_protected:Npx \@@_pdf_link_begin:nnnw #1#2#3
- {
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D startlink ~ }
- { \tex_pdfstartlink:D }
- attr {#1}
- #2 {#3}
- }
-\cs_new_protected:Npx \driver_pdf_link_end:
- {
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D endlink \scan_stop: }
- { \tex_pdfendlink:D }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_link_last:}
-% Formatted for direct use.
-% \begin{macrocode}
-\cs_new:Npx \driver_pdf_link_last:
- {
- \exp_not:N \tex_the:D
- \cs_if_exist:NTF \tex_pdffeedback:D
- { \exp_not:N \tex_pdffeedback:D lastlink \scan_stop: }
- { \exp_not:N \tex_pdflastlink:D }
- ~ 0 ~ R
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_link_margin:n}
-% A simple task: pass the data to the primitive.
-% \begin{macrocode}
-\cs_new_protected:Npx \driver_pdf_link_margin:n #1
- {
- \cs_if_exist:NTF \tex_pdfvariable:D
- { \exp_not:N \tex_pdfvariable:D linkmargin }
- { \exp_not:N \tex_pdflinkmargin:D }
- \exp_not:N \dim_eval:n {#1} \scan_stop:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_destination:nn, \driver_pdf_destination_rectangle:nn}
-% 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:Npx \driver_pdf_destination:nn #1#2
- {
- \cs_if_exist:NTF \tex_pdfextension:D
- { \exp_not:N \tex_pdfextension:D dest ~ }
- { \exp_not:N \tex_pdfdest:D }
- name {#1}
- \exp_not:N \str_case:nnF {#2}
- {
- { xyz } { xyz }
- { fit } { fit }
- { fitb } { fitb }
- { fitbh } { fitbh }
- { fitbv } { fitbv }
- { fith } { fith }
- { fitv } { fitv }
- }
- { xyz ~ zoom \exp_not:N \fp_eval:n { #2 * 10 } }
- \scan_stop:
- }
-\cs_new_protected:Npx \driver_pdf_destination_rectangle:nn #1#2
- {
- \group_begin:
- \hbox_set:Nn \l_@@_internal_box {#2}
- \cs_if_exist:NTF \tex_pdfextension:D
- { \exp_not:N \tex_pdfextension:D dest ~ }
- { \exp_not:N \tex_pdfdest:D }
- name {#1}
- fitr ~
- width \exp_not:N \box_wd:N \l_@@_internal_box
- height \exp_not:N \box_ht:N \l_@@_internal_box
- depth \exp_not:N \box_dp:N \l_@@_internal_box
- \box_use:N \l_@@_internal_box
- \group_end:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Catalogue entries}
-%
-% \begin{macro}{\driver_pdf_catalog_gput:nn, \driver_pdf_info_gput:nn}
-% \begin{macrocode}
-\cs_new_protected:Npx \driver_pdf_catalog_gput:nn #1#2
- {
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D catalog }
- { \tex_pdfcatalog:D }
- { / #1 ~ #2 }
- }
-\cs_new_protected:Npx \driver_pdf_info_gput:nn #1#2
- {
- \cs_if_exist:NTF \tex_pdfextension:D
- { \tex_pdfextension:D info }
- { \tex_pdfinfo:D }
- { / #1 ~ #2 }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Objects}
-%
-% \begin{variable}{\g_@@_pdf_object_prop}
-% For tracking objects to allow finalisation.
-% \begin{macrocode}
-\prop_new:N \g_@@_pdf_object_prop
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\driver_pdf_object_new:nn}
-% \begin{macro}[EXP]{\driver_pdf_object_ref:n}
-% Declaring objects means reserving at the PDF level plus starting
-% tracking.
-% \begin{macrocode}
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1#2
- {
- \cs_new_protected:Npx \driver_pdf_object_new:nn ##1##2
- {
- #1 reserveobjnum ~
- \int_const:cn
- { c_@@_pdf_object_ \exp_not:N \tl_to_str:n {##1} _int }
- {#2}
- \prop_gput:Nnn \exp_not:N \g_@@_pdf_object_prop {##1} {##2}
- }
- }
- \cs_if_exist:NTF \tex_pdfextension:D
- {
- \@@_tmp:w
- { \tex_pdfextension:D obj ~ }
- { \exp_not:N \tex_pdffeedback:D lastobj }
- }
- { \@@_tmp:w { \tex_pdfobj:D } { \tex_pdflastobj:D } }
-\group_end:
-\cs_new:Npn \driver_pdf_object_ref:n #1
- { \int_use:c { c_@@_pdf_object_ \tl_to_str:n {#1} _int } ~ 0 ~ R }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_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}
-\group_begin:
- \cs_set_protected:Npn \@@_tmp:w #1
- {
- \cs_new_protected:Npn \driver_pdf_object_write:nn ##1##2
- {
- \tex_immediate:D #1 useobjnum ~
- \int_use:c
- { c_@@_pdf_object_ \tl_to_str:n {##1} _int }
- \str_case_e:nn
- { \prop_item:Nn \g_@@_pdf_object_prop {##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_if_exist:NTF \tex_pdfextension:D
- { \@@_tmp:w { \tex_pdfextension:D obj ~ } }
- { \@@_tmp:w { \tex_pdfobj:D } }
-\group_end:
-\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}
-%
-% \subsubsection{Structure}
-%
-% \begin{macro}{\driver_pdf_compresslevel:n}
-% \begin{macro}{\driver_pdf_compress_objects:n}
-% \begin{macro}{\@@_pdf_objcompresslevel:n}
-% Simply pass data to the engine.
-% \begin{macrocode}
-\cs_new_protected:Npx \driver_pdf_compresslevel:n #1
- {
- \exp_not:N \tex_global:D
- \cs_if_exist:NTF \tex_pdfcompresslevel:D
- { \tex_pdfcompresslevel:D }
- { \tex_pdfvariable:D compresslevel }
- \exp_not:N \int_value:w \exp_not:N \int_eval:n {#1} \scan_stop:
- }
-\cs_new_protected:Npn \driver_pdf_compress_objects:n #1
- {
- \str_if_eq:nnTF {#1} { true }
- { \@@_pdf_objcompresslevel:n { 2 } }
- { \@@_pdf_objcompresslevel:n { 0 } }
- }
-\cs_new_protected:Npx \@@_pdf_objcompresslevel:n #1
- {
- \exp_not:N \tex_global:D
- \cs_if_exist:NTF \tex_pdfobjcompresslevel:D
- { \tex_pdfobjcompresslevel:D }
- { \tex_pdfvariable:D objcompresslevel }
- #1 \scan_stop:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n}
-% At present, we don't have a primitive for the major version in \pdfTeX{},
-% but we anticipate one \ldots
-% \begin{macrocode}
-\cs_new_protected:Npx \driver_pdf_version_major_gset:n #1
- {
- \cs_if_exist:NTF \tex_pdfvariable:D
- {
- \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:
- }
- }
- {
- \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:
- }
- }
- }
-\cs_new_protected:Npx \driver_pdf_version_minor_gset:n #1
- {
- \exp_not:N \tex_global:D
- \cs_if_exist:NTF \tex_pdfminorversion:D
- { \exp_not:N \tex_pdfminorversion:D }
- { \tex_pdfvariable:D minorversion }
- \exp_not:N \int_eval:n {#1} \scan_stop:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\driver_pdf_version_major:, \driver_pdf_version_minor:}
-% At present, we don't have a primitive for the major version!
-% \begin{macrocode}
-\cs_new:Npx \driver_pdf_version_major:
- {
- \cs_if_exist:NTF \tex_pdfvariable:D
- {
- \int_compare:nNnTF \tex_luatexversion:D > { 106 }
- { \exp_not:N \tex_the:D \tex_pdfvariable:D majorversion }
- { 1 }
- }
- {
- \cs_if_exist:NTF \tex_pdfmajorversion:D
- { \exp_not:N \tex_the:D \tex_pdfmajorversion:D }
- { 1 }
- }
- }
-\cs_new:Npx \driver_pdf_version_minor:
- {
- \exp_not:N \tex_the:D
- \cs_if_exist:NTF \tex_pdfminorversion:D
- { \exp_not:N \tex_pdfminorversion:D }
- { \tex_pdfvariable:D minorversion }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macrocode}
-%</pdfmode>
-% \end{macrocode}
-%
-% \subsection{\texttt{dvipdfmx} driver}
-%
-% \begin{macrocode}
-%<*dvipdfmx|xdvipdfmx>
-% \end{macrocode}
-%
-% \begin{macro}{\@@_pdf:n, \@@_pdf:x}
-% A generic function for the driver PDF specials: used where we can.
-% \begin{macrocode}
-\cs_new_protected:Npx \@@_pdf:n #1
- { \@@_literal:n { pdf: #1 } }
-\cs_generate_variant:Nn \@@_pdf:n { x }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Catalogue entries}
-%
-% \begin{macro}{\driver_pdf_catalog_gput:nn, \driver_pdf_info_gput:nn}
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_catalog_gput:nn #1#2
- { \@@_pdf:n { put ~ @catalog << /#1 ~ #2 >> } }
-\cs_new_protected:Npn \driver_pdf_info_gput:nn #1#2
- { \@@_pdf:n { docinfo << /#1 ~ #2 >> } }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Objects}
-%
-% \begin{variable}{\g_@@_pdf_object_int, \g_@@_pdf_object_prop}
-% For tracking objects to allow finalisation.
-% \begin{macrocode}
-\int_new:N \g_@@_pdf_object_int
-\prop_new:N \g_@@_pdf_object_prop
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\driver_pdf_object_new:nn}
-% \begin{macro}[EXP]{\driver_pdf_object_ref: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 \driver_pdf_object_new:nn #1#2
- {
- \int_gincr:N \g_@@_pdf_object_int
- \int_const:cn
- { g_@@_pdf_object_ \tl_to_str:n {#1} _int }
- { \g_@@_pdf_object_int }
- \prop_gput:Nnn \g_@@_pdf_object_prop {#1} {#2}
- }
-\cs_new:Npn \driver_pdf_object_ref:n #1
- { @driver.obj \int_use:c { g_@@_pdf_object_ \tl_to_str:n {#1} _int } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_object_write:nn}
-% \begin{macro}{\@@_pdf_object_write:nnn}
-% \begin{macro}
-% {
-% \@@_pdf_object_write_array:nn ,
-% \@@_pdf_object_write_dict:nn ,
-% \@@_pdf_object_write_fstream:nn ,
-% \@@_pdf_object_write_stream:nn
-% }
-% \begin{macro}{\@@_pdf_object_write_stream:nnnn}
-% This is where we choose the actual type.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_object_write:nn #1#2
- {
- \exp_args:Nx \@@_pdf_object_write:nnn
- { \prop_item:Nn \g_@@_pdf_object_prop {#1} } {#1} {#2}
- }
-\cs_new_protected:Npn \@@_pdf_object_write:nnn #1#2#3
- { \use:c { @@_pdf_object_write_ #1 :nn } {#2} {#3} }
-\cs_new_protected:Npn \@@_pdf_object_write_array:nn #1#2
- {
- \@@_pdf:x
- {
- obj ~ \driver_pdf_object_ref:n {#1} ~
- [ ~ \exp_not:n {#2} ~ ]
- }
- }
-\cs_new_protected:Npn \@@_pdf_object_write_dict:nn #1#2
- {
- \@@_pdf:x
- {
- obj ~ \driver_pdf_object_ref:n {#1} ~
- << ~ \exp_not:n {#2} ~ >>
- }
- }
-\cs_new_protected:Npn \@@_pdf_object_write_fstream:nn #1#2
- { \@@_pdf_object_write_stream:nnnn { f } {#1} #2 }
-\cs_new_protected:Npn \@@_pdf_object_write_stream:nn #1#2
- { \@@_pdf_object_write_stream:nnnn { } {#1} #2 }
-\cs_new_protected:Npn \@@_pdf_object_write_stream:nnnn #1#2#3#4
- {
- \@@_pdf:x
- {
- #1 stream ~ \driver_pdf_object_ref:n {#2} ~
- ( \exp_not:n {#4} ) ~ << \exp_not:n {#3} >>
-
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Annotations}
-%
-% \begin{variable}{\g_@@_landscape_bool}
-% There is a bug in \texttt{(x)dvipdfmx} which means annotations do
-% not rotate. As such, we need to know if landscape is active.
-% \begin{macrocode}
-\bool_new:N \g_@@_landscape_bool
-%<*package>
-\AtBeginDocument
- {
- \cs_if_exist:NT \landscape
- {
- \tl_put_right:Nn \landscape
- { \bool_gset_true:N \g_@@_landscape_bool }
- \tl_put_left:Nn \endlandscape
- { \bool_gset_false:N \g_@@_landscape_bool }
- }
- }
-%</package>
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\g_@@_pdf_annotation_int}
-% Needed as objects which are not annotations could be created.
-% \begin{macrocode}
-\int_new:N \g_@@_pdf_annotation_int
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}{\driver_pdf_annotation:nnnn, \@@_pdf_annotation:nnnn}
-% Simply pass the raw data through, just dealing with evaluation of dimensions.
-% The only wrinkle is landscape: we have to adjust by hand.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_annotation:nnnn #1#2#3#4
- {
- \bool_if:NTF \g_@@_landscape_bool
- {
- \box_move_up:nn {#2}
- {
- \vbox:n
- {
- \@@_pdf_annotation:nnnn
- { #2 + #3 } {#1} { 0pt } {#4}
- }
- }
- }
- { \@@_pdf_annotation:nnnn {#1} {#2} {#3} {#4} }
- }
-\cs_new_protected:Npn \@@_pdf_annotation:nnnn #1#2#3#4
- {
- \int_gincr:N \g_@@_pdf_object_int
- \int_gset_eq:NN \g_@@_pdf_annotation_int \g_@@_pdf_object_int
- \@@_pdf:x
- {
- ann ~ @driver.obj \int_use:N \g_@@_pdf_object_int \c_space_tl
- width ~ \dim_eval:n {#1} ~
- height ~ \dim_eval:n {#2} ~
- depth ~ \dim_eval:n {#3} ~
- << #4 >>
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}
-% {\driver_pdf_link_begin_goto:nnw, \driver_pdf_link_begin_user:nnw}
-% \begin{macro}{\@@_pdf_link_begin:n}
-% \begin{macro}{\driver_pdf_link_end:}
-% All created using the same internals.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_link_begin_goto:nnw #1#2
- { \@@_pdf_link_begin:n { #1 /Subtype /Link /A << /S /GoTo /D ( #2 ) >> } }
-\cs_new_protected:Npn \driver_pdf_link_begin_user:nnw #1#2
- { \@@_pdf_link_begin:n {#1#2} }
-\cs_new_protected:Npn \@@_pdf_link_begin:n #1
- {
- \@@_pdf:n
- {
- bann
- <<
- /Type /Annot
- #1
- >>
- }
- }
-\cs_new_protected:Npn \driver_pdf_link_end:
- { \@@_pdf:n { eann } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_link_last:}
-% Data not available.
-% \begin{macrocode}
-\cs_new:Npn \driver_pdf_link_last: { }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_link_margin:n}
-% Pass to \texttt{dvipdfmx}.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_link_margin:n #1
- { \@@_literal:x { dvipdfmx:config~g~ \dim_eval:n {#1} } }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\driver_pdf_destination:nn, \driver_pdf_destination_rectangle:nn}
-% 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 driver data for \texttt{@xpos} and \texttt{@ypos}.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_destination:nn #1#2
- {
- \@@_pdf:x
- {
- 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 }
- }
- { /XYZ ~ @xpos ~ @ypos ~ \fp_eval:n { (#2) / 100 } }
- ]
- }
- }
-\cs_new_protected:Npn \driver_pdf_destination_rectangle:nn #1#2
- {
- \group_begin:
- \hbox_set:Nn \l_@@_internal_box {#2}
- \box_move_down:nn { \box_dp:N \l_@@_internal_box }
- {
- \hbox:n
- {
- \@@_pdf:n { obj ~ @driver_#1_llx ~ @xpos }
- \@@_pdf:n { obj ~ @driver_#1_lly ~ @ypos }
- }
- }
- \box_use:N \l_@@_internal_box
- \box_move_up:nn { \box_ht:N \l_@@_internal_box }
- {
- \hbox:n
- {
- \@@_pdf:n
- {
- dest ~ (#1)
- [
- @thispage
- /FitR ~
- @driver_#1_llx ~ @driver_#1_lly ~
- @xpos ~ @ypos
- ]
- }
- }
- }
- \group_end:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Structure}
-%
-% \begin{macro}{\driver_pdf_compresslevel:n}
-% \begin{macro}{\driver_pdf_compress_objects:n}
-% Pass data to the driver: these are a one-shot.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_compresslevel:n #1
- { \@@_literal:x { dvipdfmx:config~z~ \int_eval:n {#1} } }
-\cs_new_protected:Npn \driver_pdf_compress_objects:n #1
- {
- \str_if_eq:nnF {#1} { true }
- { \@@_literal:n { dvipdfmx:config~C~0x40 } }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n}
-% We start with the assumption that the default is active.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_version_major:n #1
- {
- \cs_gset:Npx \driver_pdf_version_major: { \int_eval:n {#1} }
- \@@_literal:x { pdf:majorversion \driver_pdf_version_major: }
- }
-\cs_new_protected:Npn \driver_pdf_version_minor:n #1
- {
- \cs_gset:Npx \driver_pdf_version_minor: { \int_eval:n {#1} }
- \@@_literal:x { pdf:minorversion \driver_pdf_version_minor: }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\driver_pdf_version_major:, \driver_pdf_version_minor:}
-% We start with the assumption that the default is active.
-% \begin{macrocode}
-\cs_new:Npn \driver_pdf_version_major: { 1 }
-\cs_new:Npn \driver_pdf_version_minor: { 5 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macrocode}
-%</dvipdfmx|xdvipdfmx>
-% \end{macrocode}
-%
-% \subsection{\texttt{dvisvgm} driver}
-%
-% \begin{macrocode}
-%<*dvisvgm>
-% \end{macrocode}
-%
-% \subsubsection{Catalogue entries}
-%
-% \begin{macro}{\driver_pdf_catalog_gput:nn, \driver_pdf_info_gput:nn}
-% No-op.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_catalog_gput:nn #1#2 { }
-\cs_new_protected:Npn \driver_pdf_info_gput:nn #1#2 { }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Objects}
-%
-% \begin{macro}{\driver_pdf_object_new:nn}
-% \begin{macro}[EXP]{\driver_pdf_object_ref:n}
-% \begin{macro}{\driver_pdf_object_write:nn}
-% All no-ops here.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_object_new:nn #1#2 { }
-\cs_new:Npn \driver_pdf_object_ref:n #1 { }
-\cs_new_protected:Npn \driver_pdf_object_write:nn #1#2 { }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \subsubsection{Structure}
-%
-% \begin{macro}{\driver_pdf_compresslevel:n}
-% \begin{macro}{\driver_pdf_compress_objects:n}
-% These are all no-ops.
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_compresslevel:n #1 { }
-\cs_new_protected:Npn \driver_pdf_compress_objects:n #1 { }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}
-% {\driver_pdf_version_major_gset:n, \driver_pdf_version_minor_gset:n}
-% Data not available!
-% \begin{macrocode}
-\cs_new_protected:Npn \driver_pdf_version_major_gset:n #1 { }
-\cs_new_protected:Npn \driver_pdf_version_minor_gset:n #1 { }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[EXP]{\driver_pdf_version_major:, \driver_pdf_version_minor:}
-% Data not available!
-% \begin{macrocode}
-\cs_new:Npn \driver_pdf_version_major: { -1 }
-\cs_new:Npn \driver_pdf_version_minor: { -1 }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macrocode}
-%</dvisvgm>
-% \end{macrocode}
-%
-% \begin{macrocode}
-%</initex|package>
-% \end{macrocode}
-%
-% \end{implementation}
-%
-% \PrintIndex