summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2017-07-15 21:27:01 +0000
committerKarl Berry <karl@freefriends.org>2017-07-15 21:27:01 +0000
commitb1ce47fe4d0e1f06d1b019c3c6eb5f1b0ecd5e14 (patch)
tree58362abe4b603bb5f6db898b9b835bc8af730b3e /Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
parent03b8dcfa3435f0265dfad4fd09aaab8f4ff9c617 (diff)
l3 (15jul17)
git-svn-id: svn://tug.org/texlive/trunk@44813 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx1739
1 files changed, 930 insertions, 809 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
index 68bb90ec8cc..c6ecb231a2f 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx
@@ -45,7 +45,7 @@
% }^^A
% }
%
-% \date{Released 2017/05/29}
+% \date{Released 2017/07/15}
%
% \maketitle
%
@@ -81,7 +81,7 @@
% \cs{__driver_box_use_clip:N} \meta{box}
% \end{syntax}
% Inserts the content of the \meta{box} at the current insertion point
-% such that any material outside of the bounding box will not be displayed
+% such that any material outside of the bounding box is not displayed
% by the driver. The material in the \meta{box} is still placed in the
% output stream: the clipping takes place at a driver level.
%
@@ -156,7 +156,7 @@
% \meta{content}
% \cs{__driver_draw_end:}
% \end{syntax}
-% Defines a drawing environment. This will be a scope for the purposes of
+% Defines a drawing environment. This is a scope for the purposes of
% the graphics state. Depending on the driver, other set up may or may not
% take place here. The natural size of the \meta{content} should be zero
% from the \TeX{} perspective: allowance for the size of the content must
@@ -186,7 +186,7 @@
% \cs{__driver_draw_move:nn} \Arg{x} \Arg{y}
% \end{syntax}
% Moves the current drawing reference point to (\meta{x}, \meta{y});
-% any active transformation matrix will apply.
+% any active transformation matrix applies.
% \end{function}
%
% \begin{function}{\__driver_draw_lineto:nn}
@@ -194,7 +194,7 @@
% \cs{__driver_draw_lineto:nn} \Arg{x} \Arg{y}
% \end{syntax}
% Adds a path from the current drawing reference point to
-% (\meta{x}, \meta{y}); any active transformation matrix will apply. Note
+% (\meta{x}, \meta{y}); any active transformation matrix applies. Note
% that nothing is drawn until a fill or stroke operation is applied, and that
% the path may be discarded or used as a clip without appearing itself.
% \end{function}
@@ -207,7 +207,7 @@
% Adds a Bezier curve path from the current drawing reference point to
% (\meta{x_3}, \meta{y_3}), using (\meta{x_1}, \meta{y_1}) and
% (\meta{x_2}, \meta{y_2}) as control points; any active transformation
-% matrix will apply. Note that nothing is drawn until a fill or stroke
+% matrix applies. Note that nothing is drawn until a fill or stroke
% operation is applied, and that the path may be discarded or used as a clip
% without appearing itself.
% \end{function}
@@ -217,7 +217,7 @@
% \cs{__driver_draw_rectangle:nnnn} \Arg{x} \Arg{y} \Arg{width} \Arg{height}
% \end{syntax}
% Adds rectangular path from (\meta{x_1}, \meta{y_1}) of \meta{height}
-% and \meta{width}; any active transformation matrix will apply. Note that
+% and \meta{width}; any active transformation matrix applies. Note that
% nothing is drawn until a fill or stroke operation is applied, and that the
% path may be discarded or used as a clip without appearing itself.
% \end{function}
@@ -239,8 +239,8 @@
% \meta{path construction}
% \cs{__driver_draw_stroke:}
% \end{syntax}
-% Draws a line alone the current path, which will also be closed when
-% \cs{__driver_draw_closestroke:} is used. The nature of the line drawn
+% Draws a line along the current path, which is also closed by
+% \cs{__driver_draw_closestroke:}. The nature of the line drawn
% is influenced by settings for
% \begin{itemize}
% \item Line thickness
@@ -259,8 +259,8 @@
% \cs{__driver_draw_fill:}
% \end{syntax}
% Fills the area surrounded by the current path: this will be closed prior
-% to filling if it is not already. The \texttt{fillstroke} version will also
-% stroke the path as described for \cs{__driver_draw_stroke:}. The fill is
+% to filling if it is not already. The \texttt{fillstroke} version also
+% strokes the path as described for \cs{__driver_draw_stroke:}. The fill is
% influenced by the setting for fill color (or the current color if no
% specific stroke color is set). The path may also be used for clipping.
% For paths which are self-intersecting or comprising multiple parts, the
@@ -325,7 +325,7 @@
% \texttt{3pt, 3pt}. An empty pattern yields a solid line.
%
% The \meta{phase} specifies an offset at the start of the cycle. For
-% example, with a pattern \texttt{3pt} a phase of \texttt{1pt} will mean
+% example, with a pattern \texttt{3pt} a phase of \texttt{1pt} means
% that the output is $2$\,pt on, $3$\,pt off, $3$\,pt on, $3$\,pt on,
% \emph{etc.}
% \end{function}
@@ -422,12 +422,12 @@
% \Arg{a} \Arg{b} \Arg{c} \Arg{d} \Arg{x} \Arg{y}
% \end{syntax}
% Inserts the \meta{box} as an hbox with the box reference point placed
-% at ($x$, $y$). The transformation matrix $[a b c d]$ will be applied
+% at ($x$, $y$). The transformation matrix $[a b c d]$ is applied
% to the box, allowing it to be in synchronisation with any scaling, rotation
% or skewing applying more generally. Note that \TeX{} material should not
-% be inserted directly into a drawing as it will not be in the correct
-% location. Also note that as for other drawing elements the box here will
-% have no size from a \TeX{} perspective.
+% be inserted directly into a drawing as it would not be in the correct
+% location. Also note that as for other drawing elements the box here
+% has no size from a \TeX{} perspective.
% \end{function}
%
% \subsection{Coordinate system transformations}
@@ -438,7 +438,7 @@
% \Arg{x} \Arg{y}
% \end{syntax}
% Applies the transformation matrix $[a b c d]$ and offset vector
-% ($x$, $y$) to the current graphic state. This will affect any subsequent
+% ($x$, $y$) to the current graphic state. This affects any subsequent
% items in the same scope but not those already given.
% \end{function}
%
@@ -487,6 +487,752 @@
%</package>
% \end{macrocode}
%
+% The order of the driver code here is such that we get somewhat logical
+% outcomes in terms of code sharing whilst keeping things readable. (Trying to
+% mix all of the code by concept is almost unmanageable.) The key parts which
+% are shared are
+% \begin{itemize}
+% \item Color support is either \texttt{dvips}-like or \texttt{pdfmode}-like.
+% \item \texttt{pdfmode} and \texttt{(x)dvipdfmx} share drawing routines.
+% \item \texttt{xdvipdfmx} is largely the same as \texttt{dvipdfmx} so
+% takes most of the same code.
+% \end{itemize}
+%
+% \subsection{Color support}
+%
+% Whilst \texttt{(x)dvipdfmx} does have its own approach to color specials,
+% it is easier to use \texttt{dvips}-like ones for all cases except direct
+% PDF output. As such the color code is collected here in two blocks.
+%
+% \subsubsection{\texttt{dvips}-style}
+%
+% \begin{macrocode}
+%<*dvisvgm|dvipdfmx|dvips|xdvipdfmx>
+% \end{macrocode}
+%
+% \begin{macro}[aux]{\@@_color_pickup:}
+% Allow for \LaTeXe{}.
+% \begin{macrocode}
+%<*package>
+\AtBeginDocument
+ {
+ \@ifpackageloaded { color }
+ {
+ \cs_new_protected:Npn \@@_color_pickup:
+ { \tl_set_eq:NN \l__color_current_tl \current@color }
+ }
+ { \cs_new_protected:Npn \@@_color_pickup: { } }
+ }
+%</package>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_color_ensure_current:}
+% \begin{macro}[aux]{\@@_color_reset:}
+% Directly set the color using the specials: no optimisation here.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_color_ensure_current:
+ {
+%<*package>
+ \@@_color_pickup:
+%</package>
+ \tex_special:D { color~push~\l__color_current_tl }
+ }
+\cs_new_protected:Npn \@@_color_reset:
+ { \tex_special:D { color~pop } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</dvisvgm|dvipdfmx|dvips|xdvipdfmx>
+% \end{macrocode}
+%
+% \subsubsection{\texttt{pdfmode}}
+%
+% \begin{macrocode}
+%<*pdfmode>
+% \end{macrocode}
+%
+% \begin{macro}[aux]{\@@_color_pickup:}
+% \begin{macro}[aux]{\@@_color_pickup_aux:}
+% The current color in driver-dependent format: pick up the package-mode
+% data if available. We end up converting back and forward in this route as
+% we store our color data in \texttt{dvips} format.
+% \begin{macrocode}
+%<*package>
+\AtBeginDocument
+ {
+ \@ifpackageloaded { color }
+ {
+ \cs_new_protected:Npn \@@_color_pickup:
+ {
+ \tl_set:Nx \l__color_current_tl
+ {
+ \exp_after:wN \@@_color_pickup_aux:w
+ \current@color ~ 0 ~ 0 ~ 0 \q_stop
+ }
+ }
+ \cs_new:Npn \@@_color_pickup_aux:w #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 \q_stop
+ {
+ \str_if_eq:nnTF {#2} { g }
+ { gray ~ #1 }
+ {
+ \str_if_eq:nnTF {#4} { rg }
+ { rgb ~ #1 ~ #2 ~ #3 }
+ {
+ \str_if_eq:nnTF {#5} { k }
+ { cmyk ~ #1 ~ #2 ~ #3 ~ #4 }
+ { gray ~ #1 }
+ }
+ }
+ }
+ }
+ { \cs_new_protected:Npn \@@_color_pickup: { } }
+ }
+%</package>
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{variable}{\l_@@_color_stack_int}
+% \pdfTeX{} and \LuaTeX{} have multiple stacks available, and to track
+% which one is in use a variable is required.
+% \begin{macrocode}
+\int_new:N \l_@@_color_stack_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\@@_color_ensure_current:}
+% \begin{macro}[aux, EXP]
+% {
+% \@@_color_convert:w, \@@_color_convert_gray:w,
+% \@@_color_convert_cmyk:w, \@@_color_convert_rgb:w
+% }
+% \begin{macro}[aux]{\@@_color_reset:}
+% There is a dedicated primitive/primitive interface for setting colors.
+% As with scoping, this approach is not suitable for cached operations.
+% Since we are using the \texttt{dvips} format to store color, there is a
+% bit of work to correctly place it in the output.
+% \begin{macrocode}
+\cs_new_protected:Npx \@@_color_ensure_current:
+ {
+%<*package>
+ \exp_not:N \@@_color_pickup:
+%</package>
+ \cs_if_exist:NTF \luatex_pdfextension:D
+ { \luatex_pdfextension:D colorstack }
+ { \pdftex_pdfcolorstack:D }
+ \exp_not:N \l_@@_color_stack_int push
+ {
+ \exp_not:N \exp_after:wN
+ \exp_not:N \@@_color_convert:w
+ \exp_not:N \l__color_current_tl
+ \c_space_tl 0 ~ 0 ~ 0
+ \exp_not:N \q_stop
+ }
+ }
+\cs_new:Npn \@@_color_convert:w #1 ~
+ { \use:c { @@_color_convert_ #1 :w } }
+\cs_new:Npn \@@_color_convert_gray:w #1 ~ #2 \q_stop
+ { #1 ~ g ~ #1 ~ G }
+\cs_new:Npn \@@_color_convert_cmyk:w #1 ~ #2 ~ #3 ~ #4 \q_stop
+ { #1 ~ #2 ~ #3 ~ rg ~ #1 ~ #2 ~ #3 ~ RG }
+\cs_new:Npn \@@_color_convert_rgb:w #1 ~ #2 ~ #3 ~ #4 ~ #5 \q_stop
+ { #1 ~ #2 ~ #3 ~ #4 ~ k ~ #1 ~ #2 ~ #3 ~ #4 ~ K }
+\cs_new_protected:Npx \@@_color_reset:
+ {
+ \cs_if_exist:NTF \luatex_pdfextension:D
+ { \luatex_pdfextension:D colorstack }
+ { \pdftex_pdfcolorstack:D }
+ \exp_not:N \l_@@_color_stack_int pop \scan_stop:
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macrocode}
+%</pdfmode>
+% \end{macrocode}
+%
+% \subsection{\texttt{dvips} driver}
+%
+% \begin{macrocode}
+%<*dvips>
+% \end{macrocode}
+%
+% \subsubsection{Basics}
+%
+% \begin{macro}[int]{\@@_literal:n}
+% In the case of \texttt{dvips} there is no build-in saving of the current
+% position, and so some additional PostScript is required to set up the
+% transformation matrix and also to restore it afterwards. Notice the use
+% of the stack to save the current position \enquote{up front} and to
+% move back to it at the end of the process.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_literal:n #1
+ {
+ \tex_special:D
+ {
+ ps:
+ currentpoint~
+ currentpoint~translate~
+ #1 ~
+ neg~exch~neg~exch~translate
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_scope_begin:, \@@_scope_end:}
+% Scope saving/restoring is done directly with no need to worry about the
+% transformation matrix. General scoping is only for the graphics stack so
+% the lower-cost |gsave|/|grestore| pair are used.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_scope_begin:
+ { \tex_special:D { ps:gsave } }
+\cs_new_protected:Npn \@@_scope_end:
+ { \tex_special:D { ps:grestore } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Driver-specific auxiliaries}
+%
+% \begin{macro}[int, EXP]{\@@_absolute_lengths:n}
+% The \texttt{dvips} driver scales all absolute dimensions based
+% on the output resolution selected and any \TeX{} magnification. Thus
+% for any operation involving absolute lengths there is a correction to
+% make. This is based on \texttt{normalscale} from \texttt{special.pro}
+% but using the stack rather than a definition to save the current matrix.
+% \begin{macrocode}
+\cs_new:Npn \@@_absolute_lengths:n #1
+ {
+ matrix~currentmatrix~
+ Resolution~72~div~VResolution~72~div~scale~
+ DVImag~dup~scale~
+ #1 ~
+ setmatrix
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Box operations}
+%
+% \begin{macro}{\@@_box_use_clip:N}
+% Much the same idea as for the PDF mode version but with a slightly
+% different syntax for creating the clip path. To avoid any scaling
+% issues we need the absolute length auxiliary here.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_clip:N #1
+ {
+ \@@_scope_begin:
+ \@@_literal:n
+ {
+ \@@_absolute_lengths:n
+ {
+ 0 ~
+ \dim_to_decimal_in_bp:n { \box_dp:N #1 } ~
+ \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
+ \dim_to_decimal_in_bp:n { -\box_ht:N #1 - \box_dp:N #1 } ~
+ rectclip
+ }
+ }
+ \hbox_overlap_right:n { \box_use:N #1 }
+ \@@_scope_end:
+ \skip_horizontal:n { \box_wd:N #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_box_use_rotate:Nn}
+% Rotating using \texttt{dvips} does not require that the box dimensions
+% are altered and has a very convenient built-in operation. Zero rotation
+% must be written as |0| not |-0| so there is a quick test.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
+ {
+ \@@_scope_begin:
+ \@@_literal:n
+ {
+ \fp_compare:nNnTF {#2} = \c_zero_fp
+ { 0 }
+ { \fp_eval:n { round ( -#2 , 5 ) } } ~
+ rotate
+ }
+ \box_use:N #1
+ \@@_scope_end:
+ }
+% \end{macro}
+%
+% \begin{macro}{\@@_box_use_scale:Nnn}
+% The \texttt{dvips} driver once again has a dedicated operation we can
+% use here.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
+ {
+ \@@_scope_begin:
+ \@@_literal:n
+ {
+ \fp_eval:n { round ( #2 , 5 ) } ~
+ \fp_eval:n { round ( #3 , 5 ) } ~
+ scale
+ }
+ \hbox_overlap_right:n { \box_use:N #1 }
+ \@@_scope_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Images}
+%
+% \begin{macro}[int]{\@@_image_getbb_eps:n}
+% Simply use the generic function.
+% \begin{macrocode}
+\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_image_include_eps:n}
+% The special syntax is relatively clear here: remember we need PostScript
+% sizes here.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_image_include_eps:n #1
+ {
+ \tex_special:D { PSfile = #1 }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Drawing}
+%
+% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x}
+% Literals with no positioning (using |ps:| each one is positioned but
+% cut off from everything else, so no good for the stepwise approach needed
+% here).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_literal:n #1
+ { \tex_special:D { ps:: ~ #1 } }
+\cs_generate_variant:Nn \@@_draw_literal:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_draw_begin:, \@@_draw_end:}
+% The |ps::[begin]| special here deals with positioning but allows us to
+% continue on to a matching |ps::[end]|: contrast with |ps:|, which positions
+% but where we can't split material between separate calls. The
+% |@beginspecial|/|@endspecial| pair are from |special.pro| and correct the
+% scale and $y$-axis direction. The reference point at the start of the box
+% is saved (as |l3x|/|l3y|) as it is needed when inserting various items.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_begin:
+ {
+ \tex_special:D { ps::[begin] }
+ \tex_special:D { ps::~save }
+ \tex_special:D { ps::~/l3x~currentpoint~/l3y~exch~def~def }
+ \tex_special:D { ps::~@beginspecial }
+ }
+\cs_new_protected:Npn \@@_draw_end:
+ {
+ \tex_special:D { ps::~@endspecial }
+ \tex_special:D { ps::~restore }
+ \tex_special:D { ps::[end] }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_draw_scope_begin:, \@@_draw_scope_end:}
+% Scope here may need to contain saved definitions, so the entire memory
+% rather than just the graphic state has to be sent to the stack.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_scope_begin:
+ { \@@_draw_literal:n { save } }
+\cs_new_protected:Npn \@@_draw_scope_end:
+ { \@@_draw_literal:n { restore } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_draw_moveto:nn, \@@_draw_lineto:nn}
+% \begin{macro}[int]{\@@_draw_rectangle:nnnn}
+% \begin{macro}[int]{\@@_draw_curveto:nnnnnn}
+% Path creation operations mainly resolve directly to PostScript primitive
+% steps, with only the need to convert to \texttt{bp}. Notice that
+% \texttt{x}-type expansion is included here to ensure that any variable
+% values are forced to literals before any possible caching. There is
+% no native rectangular path command (without also clipping, filling or
+% stroking), so that task is done using a small amount of PostScript.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_moveto:nn #1#2
+ {
+ \@@_draw_literal:x
+ { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ moveto }
+ }
+\cs_new_protected:Npn \@@_draw_lineto:nn #1#2
+ {
+ \@@_draw_literal:x
+ { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ lineto }
+ }
+\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4
+ {
+ \@@_draw_literal:x
+ {
+ \dim_to_decimal_in_bp:n {#4} ~ \dim_to_decimal_in_bp:n {#3} ~
+ \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~
+ moveto~dup~0~rlineto~exch~0~exch~rlineto~neg~0~rlineto~closepath
+ }
+ }
+\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_draw_literal:x
+ {
+ \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~
+ \dim_to_decimal_in_bp:n {#3} ~ \dim_to_decimal_in_bp:n {#4} ~
+ \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~
+ curveto
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:}
+% \begin{variable}[aux]{\g_@@_draw_eor_bool}
+% The even-odd rule here can be implemented as a simply switch.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_evenodd_rule:
+ { \bool_gset_true:N \g_@@_draw_eor_bool }
+\cs_new_protected:Npn \@@_draw_nonzero_rule:
+ { \bool_gset_false:N \g_@@_draw_eor_bool }
+\bool_new:N \g_@@_draw_eor_bool
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{macro}[int]
+% {
+% \@@_draw_closepath: ,
+% \@@_draw_stroke: ,
+% \@@_draw_closestroke: ,
+% \@@_draw_fill: ,
+% \@@_draw_fillstroke: ,
+% \@@_draw_clip: ,
+% \@@_draw_discardpath:
+% }
+% \begin{variable}[aux]{\g_@@_draw_clip_bool}
+% Unlike PDF, PostScript doesn't track separate colors for strokes and other
+% elements. It is also desirable to have the |clip| keyword after a stroke or
+% fill. To achieve those outcomes, there is some work to do. For color, if a
+% stroke or fill color is defined it is used for the relevant operation, with
+% a graphic scope inserted as required. That does mean that once such a color
+% is set all further uses inside the same scope have to use scoping: see also
+% the color set up functions. For clipping, the required ordering is achieved
+% using a \TeX{} switch. All of the operations end with a new path instruction
+% as they do not terminate (again in contrast to PDF).
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_closepath:
+ { \@@_draw_literal:n { closepath } }
+\cs_new_protected:Npn \@@_draw_stroke:
+ {
+ \@@_draw_literal:n { currentdict~/l3sc~known~{gsave~l3sc}~if }
+ \@@_draw_literal:n { stroke }
+ \@@_draw_literal:n { currentdict~/l3sc~known~{grestore}~if }
+ \bool_if:NT \g_@@_draw_clip_bool
+ {
+ \@@_draw_literal:x
+ {
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ clip
+ }
+ }
+ \@@_draw_literal:n { newpath }
+ \bool_gset_false:N \g_@@_draw_clip_bool
+ }
+\cs_new_protected:Npn \@@_draw_closestroke:
+ {
+ \@@_draw_closepath:
+ \@@_draw_stroke:
+ }
+\cs_new_protected:Npn \@@_draw_fill:
+ {
+ \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
+ \@@_draw_literal:x
+ {
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ fill
+ }
+ \@@_draw_literal:n { currentdict~/l3fc~known~{grestore}~if }
+ \bool_if:NT \g_@@_draw_clip_bool
+ {
+ \@@_draw_literal:x
+ {
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ clip
+ }
+ }
+ \@@_draw_literal:n { newpath }
+ \bool_gset_false:N \g_@@_draw_clip_bool
+ }
+\cs_new_protected:Npn \@@_draw_fillstroke:
+ {
+ \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
+ \@@_draw_literal:x
+ {
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ fill
+ }
+ \@@_draw_literal:n { currentdict~/l3fc~known~{grestore}~if }
+ \@@_draw_literal:n { currentdict~/l3sc~known~{gsave~l3sc}~if }
+ \@@_draw_literal:n { stroke }
+ \@@_draw_literal:n { currentdict~/l3sc~known~{grestore}~if }
+ \bool_if:NT \g_@@_draw_clip_bool
+ {
+ \@@_draw_literal:x
+ {
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ clip
+ }
+ }
+ \@@_draw_literal:n { newpath }
+ \bool_gset_false:N \g_@@_draw_clip_bool
+ }
+\cs_new_protected:Npn \@@_draw_clip:
+ { \bool_gset_true:N \g_@@_draw_clip_bool }
+\bool_new:N \g_@@_draw_clip_bool
+\cs_new_protected:Npn \@@_draw_discardpath:
+ {
+ \bool_if:NT \g_@@_draw_clip_bool
+ {
+ \@@_draw_literal:x
+ {
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ clip
+ }
+ }
+ \@@_draw_literal:n { newpath }
+ \bool_gset_false:N \g_@@_draw_clip_bool
+ }
+% \end{macrocode}
+% \end{variable}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_draw_dash:nn}
+% \begin{macro}[aux]{\@@_draw_dash:n}
+% \begin{macro}[int]{\@@_draw_linewidth:n}
+% \begin{macro}[int]{\@@_draw_miterlimit:n}
+% \begin{macro}[int]
+% {
+% \@@_draw_cap_butt:, \@@_draw_cap_round:, \@@_draw_cap_rectangle:,
+% \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel:
+% }
+% Converting paths to output is again a case of mapping directly to
+% PostScript operations.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_dash:nn #1#2
+ {
+ \@@_draw_literal:x
+ {
+ [ ~
+ \clist_map_function:nN {#1} \@@_draw_dash:n
+ ] ~
+ \dim_to_decimal_in_bp:n {#2} ~ setdash
+ }
+ }
+\cs_new:Npn \@@_draw_dash:n #1
+ { \dim_to_decimal_in_bp:n {#1} ~ }
+\cs_new_protected:Npn \@@_draw_linewidth:n #1
+ {
+ \@@_draw_literal:x
+ { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth }
+ }
+\cs_new_protected:Npn \@@_draw_miterlimit:n #1
+ { \@@_draw_literal:x { \fp_eval:n {#1} ~ setmiterlimit } }
+\cs_new_protected:Npn \@@_draw_cap_butt:
+ { \@@_draw_literal:n { 0 ~ setlinecap } }
+\cs_new_protected:Npn \@@_draw_cap_round:
+ { \@@_draw_literal:n { 1 ~ setlinecap } }
+\cs_new_protected:Npn \@@_draw_cap_rectangle:
+ { \@@_draw_literal:n { 2 ~ setlinecap } }
+\cs_new_protected:Npn \@@_draw_join_miter:
+ { \@@_draw_literal:n { 0 ~ setlinejoin } }
+\cs_new_protected:Npn \@@_draw_join_round:
+ { \@@_draw_literal:n { 1 ~ setlinejoin } }
+\cs_new_protected:Npn \@@_draw_join_bevel:
+ { \@@_draw_literal:n { 2 ~ setlinejoin } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\_@@_draw_color_reset:}
+% \begin{macro}[int]
+% {
+% \@@_draw_color_cmyk:nnnn ,
+% \@@_draw_color_cmyk_fill:nnnn ,
+% \@@_draw_color_cmyk_stroke:nnnn
+% }
+% \begin{macro}[int]
+% {
+% \@@_draw_color_gray:n ,
+% \@@_draw_color_gray_fill:n ,
+% \@@_draw_color_gray_stroke:n
+% }
+% \begin{macro}[int]
+% {
+% \@@_draw_color_rgb:nnn ,
+% \@@_draw_color_rgb_fill:nnn ,
+% \@@_draw_color_rgb_stroke:nnn
+% }
+% To allow color to be defined for strokes and fills separately and to
+% respect scoping, the data needs to be stored at the PostScript level.
+% We cannot undefine (local) fill/stroke colors once set up but we can
+% set them blank to improve performance slightly.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_color_reset:
+ {
+ \@@_draw_literal:n { currentdic~/l3fc~known~{ /l3fc~ { } ~def }~if }
+ \@@_draw_literal:n { currentdic~/l3sc~known~{ /l3sc~ { } ~def }~if }
+ }
+\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn #1#2#3#4
+ {
+ \@@_draw_literal:x
+ {
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+ \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+ setcmykcolor ~
+ }
+ \@@_draw_color_reset:
+ }
+\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn #1#2#3#4
+ {
+ \@@_draw_literal:x
+ {
+ /l3fc ~
+ {
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+ \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+ setcmykcolor
+ } ~
+ def
+ }
+ }
+\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
+ {
+ \__driver_draw_literal:x
+ {
+ /l3sc ~
+ {
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+ \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+ setcmykcolor
+ } ~
+ def
+ }
+ }
+\cs_new_protected:Npn \@@_draw_color_gray:n #1
+ {
+ \@@_draw_literal:x { fp_eval:n {#1} ~ setgray }
+ \@@_draw_color_reset:
+ }
+\cs_new_protected:Npn \@@_draw_color_gray_fill:n #1
+ { \@@_draw_literal:x { /l3fc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
+\cs_new_protected:Npn \@@_draw_color_gray_stroke:n #1
+ { \@@_draw_literal:x { /l3sc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
+\cs_new_protected:Npn \@@_draw_color_rgb:nnn #1#2#3
+ {
+ \@@_draw_literal:x
+ {
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
+ setrgbcolor
+ }
+ \@@_draw_color_reset:
+ }
+\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn #1#2#3
+ {
+ \@@_draw_literal:x
+ {
+ /l3fc ~
+ {
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
+ setrgbcolor
+ } ~
+ def
+ }
+ }
+\cs_new_protected:Npn \@@_draw_color_rgb_stroke:nnn #1#2#3
+ {
+ \@@_draw_literal:x
+ {
+ /l3sc ~
+ {
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
+ setrgbcolor
+ } ~
+ def
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_draw_transformcm:nnnnnn}
+% The first four arguments here are floats (the affine matrix), the last
+% two are a displacement vector. Once again, force evaluation to allow for
+% caching.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_transformcm:nnnnnn #1#2#3#4#5#6
+ {
+ \@@_draw_literal:x
+ {
+ [
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+ \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+ \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~
+ ] ~
+ concat
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_draw_hbox:Nnnnnnn}
+% Inside a picture |@beginspecial|/|@endspecial| are active, which is
+% normally a good thing but means that the position and scaling would be off
+% if the box was inserted directly. Instead, we need to reverse the effect of
+% the (normally desirable) shift/scaling within the box. That requires
+% knowing where the reference point for the drawing is: saved as |l3x|/|l3y|
+% at the start of the picture. Transformation here is relative to the
+% drawing origin so has to be done purely in driver code not using \TeX{}
+% offsets.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_draw_hbox:Nnnnnnn #1#2#3#4#5#6#7
+ {
+ \@@_scope_begin:
+ \tex_special:D { ps::[end] }
+ \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5} {#6} {#7}
+ \tex_special:D { ps::~72~Resolution~div~72~VResolution~div~neg~scale }
+ \tex_special:D { ps::~magscale~{1~DVImag~div~dup~scale}~if }
+ \tex_special:D { ps::~l3x~neg~l3y~neg~translate }
+ \group_begin:
+ \box_set_wd:Nn #1 { 0pt }
+ \box_set_ht:Nn #1 { 0pt }
+ \box_set_dp:Nn #1 { 0pt }
+ \box_use:N #1
+ \group_end:
+ \tex_special:D { ps::[begin] }
+ \@@_scope_end:
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</dvips>
+% \end{macrocode}
+%
% \subsection{\texttt{pdfmode} driver}
%
% \begin{macrocode}
@@ -638,58 +1384,6 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Color}
-%
-% \begin{variable}{\l_@@_color_current_tl}
-% The current color in driver-dependent format: pick up the package-mode
-% data if available.
-% \begin{macrocode}
-\tl_new:N \l_@@_color_current_tl
-\tl_set:Nn \l_@@_color_current_tl { 0~g~0~G }
-%<*package>
-\AtBeginDocument
- {
- \@ifpackageloaded { color }
- { \tl_set:Nn \l_@@_color_current_tl { \current@color } }
- { }
- }
-%</package>
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{variable}{\l_@@_color_stack_int}
-% \pdfTeX{} and \LuaTeX{} have multiple stacks available, and to track
-% which one is in use a variable is required.
-% \begin{macrocode}
-\int_new:N \l_@@_color_stack_int
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[int]{\@@_color_ensure_current:}
-% \begin{macro}[aux]{\@@_color_reset:}
-% There is a dedicated primitive/primitive interface for setting colors.
-% As with scoping, this approach is not suitable for cached operations.
-% \begin{macrocode}
-\cs_new_protected:Npx \@@_color_ensure_current:
- {
- \cs_if_exist:NTF \luatex_pdfextension:D
- { \luatex_pdfextension:D colorstack }
- { \pdftex_pdfcolorstack:D }
- \exp_not:N \l_@@_color_stack_int push
- { \exp_not:N \l_@@_color_current_tl }
- \group_insert_after:N \exp_not:N \@@_color_reset:
- }
-\cs_new_protected:Npx \@@_color_reset:
- {
- \cs_if_exist:NTF \luatex_pdfextension:D
- { \luatex_pdfextension:D colorstack }
- { \pdftex_pdfcolorstack:D }
- \exp_not:N \l_@@_color_stack_int pop \scan_stop:
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
% \subsection{Images}
%
% \begin{variable}{\l_@@_image_attr_tl}
@@ -713,64 +1407,84 @@
% and vector images but keeping the common parts, there is a little work
% to do in terms of auxiliaries. The key here is to notice that we need
% two forms of the attributes: a \enquote{short} set to allow us to
-% track for caching, and the full form to pass to the primitive. Note that
-% in |pdftex.def| the short reference is stored to be used in the inclusion
-% stage: may be required when there are more aspects to track.
+% track for caching, and the full form to pass to the primitive.
% \begin{macrocode}
\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
{
\int_zero:N \l__image_page_int
+ \tl_clear:N \l__image_pagebox_tl
\tl_set:Nx \l_@@_image_attr_tl
{
+ \tl_if_empty:NF \l__image_decode_tl
+ { :D \l__image_decode_tl }
\bool_if:NT \l__image_interpolate_bool
{ :I }
}
+ \tl_clear:N \l_@@_image_attr_tl
\@@_image_getbb_auxi:n {#1}
}
\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
{
+ \tl_clear:N \l__image_decode_tl
\bool_set_false:N \l__image_interpolate_bool
\tl_set:Nx \l_@@_image_attr_tl
{
- \int_compare:nNnT \l__image_page_int > 0
+ : \l__image_pagebox_tl
+ \int_compare:nNnT \l__image_page_int > 1
{ :P \int_use:N \l__image_page_int }
}
\@@_image_getbb_auxi:n {#1}
}
\cs_new_protected:Npn \@@_image_getbb_auxi:n #1
{
- \dim_if_exist:cTF { c__image_ #1 \l_@@_image_attr_tl _ht_dim }
+ \dim_zero:N \l__image_llx_dim
+ \dim_zero:N \l__image_lly_dim
+ \dim_if_exist:cTF { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
{
- \dim_set_eq:Nc \l__image_ht_dim
- { c__image_ #1 \l_@@_image_attr_tl _ht_dim }
- \dim_set_eq:Nc \l__image_wd_dim
- { c__image_ #1 \l_@@_image_attr_tl _wd_dim }
+ \dim_set_eq:Nc \l__image_urx_dim
+ { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
+ \dim_set_eq:Nc \l__image_ury_dim
+ { c__image_ #1 \l_@@_image_attr_tl _ury_dim }
}
{ \@@_image_getbb_auxii:n {#1} }
}
% \begin{macrocode}
% Measuring the image is done by boxing up: for PDF images we could
% use |\pdftex_pdfximagebbox:D|, but if doesn't work for other types.
+% As the box always starts at $(0,0)$ there is no need to worry about
+% the lower-left position.
% \begin{macrocode}
\cs_new_protected:Npn \@@_image_getbb_auxii:n #1
{
\tex_immediate:D \pdftex_pdfximage:D
- \bool_if:NT \l__image_interpolate_bool
- { attr ~ { /Interpolate~true } }
+ \bool_lazy_or:nnT
+ { \l__image_interpolate_bool }
+ { ! \tl_if_empty_p:N \l__image_decode_tl }
+ {
+ attr ~
+ {
+ \tl_if_empty:NF \l__image_decode_tl
+ { /Decode~[ \l__image_decode_tl ] }
+ \bool_if:NT \l__image_interpolate_bool
+ { /Interpolate~true }
+ }
+ }
\int_compare:nNnT \l__image_page_int > 0
{ page ~ \int_use:N \l__image_page_int }
+ \tl_if_empty:NF \l__image_pagebox_tl
+ { \l__image_pagebox_tl }
{#1}
\hbox_set:Nn \l__image_tmp_box
{ \pdftex_pdfrefximage:D \pdftex_pdflastximage:D }
- \dim_set:Nn \l__image_ht_dim { \box_ht:N \l__image_tmp_box }
- \dim_set:Nn \l__image_wd_dim { \box_wd:N \l__image_tmp_box }
+ \dim_set:Nn \l__image_urx_dim { \box_wd:N \l__image_tmp_box }
+ \dim_set:Nn \l__image_ury_dim { \box_ht:N \l__image_tmp_box }
\int_const:cn { c__image_ #1 \l_@@_image_attr_tl _int }
{ \tex_the:D \pdftex_pdflastximage:D }
- \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _ht_dim }
- { \l__image_ht_dim }
- \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _wd_dim }
- { \l__image_wd_dim }
+ \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
+ { \l__image_urx_dim }
+ \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _ury_dim }
+ { \l__image_ury_dim }
}
% \end{macrocode}
% \end{macro}
@@ -858,7 +1572,7 @@
% \begin{macro}[int]{\@@_box_use_rotate:Nn}
% Rotating in \texttt{(x)}dvipdmfx can be implemented using either PDF or
% driver-specific code. The former approach however is not \enquote{aware}
-% of the content of boxes: this means that any links embded will not be
+% of the content of boxes: this means that any embedded links would not be
% adjusted by the rotation. As such, the driver-native approach is prefered:
% the code therefore is similar (though not identical) to the \texttt{dvips}
% version (notice the rotation angle here is positive). As for
@@ -899,39 +1613,6 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Color}
-%
-% \begin{variable}{\l_@@_color_current_tl}
-% The current color in driver-dependent format.
-% \begin{macrocode}
-\tl_new:N \l_@@_color_current_tl
-\tl_set:Nn \l_@@_color_current_tl { [ 0 ] }
-%<*package>
-\AtBeginDocument
- {
- \@ifpackageloaded { color }
- { \tl_set:Nn \l_@@_color_current_tl { \current@color } }
- { }
- }
-%</package>
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[int]{\@@_color_ensure_current:}
-% \begin{macro}[aux]{\@@_color_reset:}
-% Directly set the color using the specials with optimisation support.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_color_ensure_current:
- {
- \tex_special:D { pdf:bcolor~\l_@@_color_current_tl }
- \group_insert_after:N \@@_color_reset:
- }
-\cs_new_protected:Npn \@@_color_reset:
- { \tex_special:D { pdf:ecolor } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
% \subsection{Images}
%
% \begin{macro}[int]
@@ -947,12 +1628,14 @@
\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
{
\int_zero:N \l__image_page_int
+ \tl_clear:N \l__image_pagebox_tl
\__image_extract_bb:n {#1}
}
\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
{
- \bool_set_false:N \l__image_interpolate_tl
+ \tl_clear:N \l__image_decode_tl
+ \bool_set_false:N \l__image_interpolate_bool
\__image_extract_bb:n {#1}
}
%</dvipdfmx>
@@ -974,7 +1657,10 @@
% \begin{macro}[aux]{\@@_image_include_auxi:nn}
% \begin{macro}[aux]{\@@_image_include_auxii:nnn, \@@_image_include_auxii:xnn}
% \begin{macro}[aux]{\@@_image_include_auxiii:nn}
-% The special syntax depends on the file type.
+% The special syntax depends on the file type. There is a difference in
+% how PDF images are best handled between |dvipdfmx| and |xdvipdfmx|: for
+% the latter it is better to use the primitive route. The relevant code for
+% that is included later in this file.
% \begin{macrocode}
\cs_new_protected:Npn \@@_image_include_eps:n #1
{
@@ -982,9 +1668,11 @@
}
\cs_new_protected:Npn \@@_image_include_jpg:n #1
{ \@@_image_include_auxi:nn {#1} { image } }
-\cs_new_eq:NN \@@_image_include_png:n \@@_image_include_png:n
+\cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n
+%<*dvipdfmx>
\cs_new_protected:Npn \@@_image_include_pdf:n #1
{ \@@_image_include_auxi:nn {#1} { epdf } }
+%</dvipdfmx>
% \end{macrocode}
% Image inclusion is set up to use the fact that each image is stored in
% the PDF as an XObject. This means that we can include repeated images
@@ -995,8 +1683,12 @@
{
\@@_image_include_auxii:xnn
{
- \int_compare:nNnT \l__image_page_int > 0
+ \tl_if_empty:NF \l__image_pagebox_tl
+ { : \l__image_pagebox_tl }
+ \int_compare:nNnT \l__image_page_int > 1
{ :P \int_use:N \l__image_page_int }
+ \tl_if_empty:NF \l__image_decode_tl
+ { :D \l__image_decode_tl }
\bool_if:NT \l__image_interpolate_bool
{ :I }
}
@@ -1012,6 +1704,12 @@
{ \@@_image_include_auxiii:nn {#2} {#1} {#3} }
}
\cs_generate_variant:Nn \@@_image_include_auxii:nnn { x }
+% \end{macrocode}
+% Inclusion using the specials is relatively straight-forward, but there
+% is one wrinkle. To get the |pagebox| correct for PDF images in all cases,
+% it is necessary to provide both that information and the |bbox| argument:
+% odd things happen otherwise!
+% \begin{macrocode}
\cs_new_protected:Npn \@@_image_include_auxiii:nnn #1#2#3
{
\int_gincr:N \g_@@_image_int
@@ -1020,11 +1718,29 @@
{
pdf:#3~
@image \int_use:c { c__image_ #1#2 _int }
- \int_compare:nNnT \l__image_page_int > 0
+ \int_compare:nNnT \l__image_page_int > 1
{ page ~ \int_use:N \l__image_page_int \c_space_tl }
+ \tl_if_empty:NF \l__image_pagebox_tl
+ {
+ pagebox ~ \l__image_pagebox_tl \c_space_tl
+ bbox ~
+ \dim_to_decimal_in_bp:n \l__image_llx_dim \c_space_tl
+ \dim_to_decimal_in_bp:n \l__image_lly_dim \c_space_tl
+ \dim_to_decimal_in_bp:n \l__image_urx_dim \c_space_tl
+ \dim_to_decimal_in_bp:n \l__image_ury_dim \c_space_tl
+ }
(#1)
- \bool_if:NT \l__image_interpolate_bool
- { <</Interpolate~true>> }
+ \bool_lazy_or:nnT
+ { \l__image_interpolate_bool }
+ { ! \tl_if_empty_p:N \l__imge_decode_tl }
+ {
+ <<
+ \tl_if_empty:NF \l__imge_decode_tl
+ { /Decode~[ \l__imge_decode_tl ] }
+ \bool_if:NT \l__image_interpolate_bool
+ { /Interpolate~true> }
+ >>
+ }
}
}
% \end{macrocode}
@@ -1043,41 +1759,6 @@
%<*xdvipdfmx>
% \end{macrocode}
%
-% \subsubsection{Color}
-%
-% \begin{macro}[int]{\@@_color_ensure_current:}
-% \begin{macro}[aux]{\@@_color_reset:}
-% Older \LaTeXe{} drivers uses \texttt{dvips}-like specials so there has to
-% be a change of set up if \pkg{color} is loaded and if the current color
-% doesn't match the pattern expected for |dvipdfmx|.
-% \begin{macrocode}
-%<*package>
-\AtBeginDocument
- {
- \@ifpackageloaded { color }
- {
- \cs_set_protected:Npn \@@_tmp:w #1 [ #2 ] #3 \q_stop
- {
- \tl_if_empty:nT {#2}
- {
- \cs_set_protected:Npn \@@_color_ensure_current:
- {
- \tex_special:D { color~push~\l_@@_color_current_tl }
- \group_insert_after:N \@@_color_reset:
- }
- \cs_set_protected:Npn \@@_color_reset:
- { \tex_special:D { color~pop } }
- }
- }
- \exp_after:wN \@@_tmp:w \current@color [ ] \q_stop
- }
- { }
- }
-%</package>
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
% \subsection{Images}
%
% \begin{macro}[int]
@@ -1085,50 +1766,99 @@
% \begin{macro}[aux]{\@@_image_getbb_auxi:nN}
% \begin{macro}[aux]{\@@_image_getbb_auxii:nnN, \@@_image_getbb_auxii:VnN}
% \begin{macro}[aux]{\@@_image_getbb_auxiii:nNnn}
+% \begin{macro}[aux]{\@@_image_getbb_auxiv:nnNnn, \@@_image_getbb_auxiv:VnNnn}
+% \begin{macro}[aux]{\@@_image_getbb_auxv:nNnn, \@@_image_getbb_auxv:nNnn}
+% \begin{macro}[aux, EXP]{\@@_image_getbb_pagebox:w}
% For \texttt{xdvipdfmx}, there are two primitives that allow us to obtain
-% the bounding box without needing \texttt{extractbb}.
+% the bounding box without needing \texttt{extractbb}. The only complexity
+% is passing the various minor variations to a common core process. The
+% \XeTeX{} primitive omits the text |box| from the page box specification,
+% so there is also some \enquote{trimming} to do here.
% \begin{macrocode}
\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
{
\int_zero:N \l__image_page_int
+ \tl_clear:N \l__image_pagebox_tl
\@@_image_getbb_auxi:nN {#1} \xetex_picfile:D
}
\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
- { \@@_image_getbb_auxi:nN {#1} \xetex_pdffile:D }
+ {
+ \tl_clear:N \l__image_decode_tl
+ \bool_set_false:N \l__image_interpolate_bool
+ \@@_image_getbb_auxi:nN {#1} \xetex_pdffile:D
+ }
\cs_new_protected:Npn \@@_image_getbb_auxi:nN #1#2
{
- \int_compare:nNnTF \l__image_page_int > 0
+ \int_compare:nNnTF \l__image_page_int > 1
{ \@@_image_getbb_auxii:VnN \l__image_page_int {#1} #2 }
{ \@@_image_getbb_auxiii:nNnn {#1} #2 }
}
\cs_new_protected:Npn \@@_image_getbb_auxii:nnN #1#2#3
- { \@@_image_getbb_auxiii:nNnn {#2} #3 { :P #1 } { page #1 } }
+ { \@@_image_getbb_aux:nNnn {#2} #3 { :P #1 } { page #1 } }
\cs_generate_variant:Nn \@@_image_getbb_auxii:nnN { V }
\cs_new_protected:Npn \@@_image_getbb_auxiii:nNnn #1#2#3#4
{
- \dim_if_exist:cTF { c__image_ #1#3 _ht_dim }
+ \tl_if_empty:NTF \l__image_pagebox_tl
+ { \@@_image_getbb_auxiv:VnNnn \l__image_pagebox_tl }
+ { \@@_image_getbb_auxv:nNnn }
+ {#1} #2 {#3} {#4}
+ }
+\cs_new_protected:Npn \@@_image_getbb_auxiv:nnNnn #1#2#3#4#5
+ {
+ \use:x
+ {
+ \@@_image_getbb_auxv:nNnn {#2} #3 { : #1 #4 }
+ { #5 ~ \@@_image_getbb_pagebox:w #1 }
+ }
+ }
+\cs_generate_variant:Nn \@@_image_getbb_auxiv:nnNnn { V }
+\cs_new_protected:Npn \@@_image_getbb_auxv:nNnn #1#2#3#4
+ {
+ \dim_zero:N \l__image_llx_dim
+ \dim_zero:N \l__image_lly_dim
+ \dim_if_exist:cTF { c__image_ #1#3 _urx_dim }
{
- \dim_set_eq:Nc \l__image_ht_dim { c__image_ #1#3 _ht_dim }
- \dim_set_eq:Nc \l__image_wd_dim { c__image_ #1#3 _wd_dim }
+ \dim_set_eq:Nc \l__image_urx_dim { c__image_ #1#3 _urx_dim }
+ \dim_set_eq:Nc \l__image_ury_dim { c__image_ #1#3 _ury_dim }
}
{ \@@_image_getbb_auxvi:nNnn {#1} #2 {#3} {#4} }
}
\cs_new_protected:Npn \@@_image_getbb_auxvi:nNnn #1#2#3#4
{
\hbox_set:Nn \l__image_tmp_box { #2 #1 ~ #4 }
- \dim_set:Nn \l__image_ht_dim { \box_ht:N \l__image_tmp_box }
- \dim_set:Nn \l__image_wd_dim { \box_wd:N \l__image_tmp_box }
- \dim_const:cn { c__image_ #1#3 _ht_dim }
- { \l__image_ht_dim }
- \dim_const:cn { c__image_ #1#3 _wd_dim }
- { \l__image_wd_dim }
+ \dim_set:Nn \l__image_utx_dim { \box_wd:N \l__image_tmp_box }
+ \dim_set:Nn \l__image_ury_dim { \box_ht:N \l__image_tmp_box }
+ \dim_const:cn { c__image_ #1#3 _urx_dim }
+ { \l__image_urx_dim }
+ \dim_const:cn { c__image_ #1#3 _ury_dim }
+ { \l__image_ury_dim }
}
+\cs_new:Npn \@@_image_getbb_pagebox:w #1 box {#1}
% \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_image_include_pdf:n}
+% For PDF images, properly supporting the |pagebox| concept in \XeTeX{}
+% is best done using the |\xetex_pdffile:D| primitive. The syntax here
+% is the same as for the image measurement part, although we know at this
+% stage that there must be some valid setting for \cs{l__image_pagebox_tl}.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_image_include_pdf:n #1
+ {
+ \xetex_pdffile:D "#1" ~
+ \int_compare:nNnT \l__image_page_int > 0
+ { page~ \int_use:N \l__image_page_int }
+ \@@_image_getbb_auxiv:VnNnn \l__image_pagebox_tl
+ }
+% \end{macrocode}
+% \end{macro}
%
% \begin{macrocode}
%</xdvipdfmx>
@@ -1474,616 +2204,6 @@
%</dvipdfmx|pdfmode|xdvipdfmx>
% \end{macrocode}
%
-% \subsection{\texttt{dvips} driver}
-%
-% \begin{macrocode}
-%<*dvips>
-% \end{macrocode}
-%
-% \subsubsection{Basics}
-%
-% \begin{macro}[int]{\@@_literal:n}
-% In the case of \texttt{dvips} there is no build-in saving of the current
-% position, and so some additional PostScript is required to set up the
-% transformation matrix and also to restore it afterwards. Notice the use
-% of the stack to save the current position \enquote{up front} and to
-% move back to it at the end of the process.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_literal:n #1
- {
- \tex_special:D
- {
- ps:
- currentpoint~
- currentpoint~translate~
- #1 ~
- neg~exch~neg~exch~translate
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_scope_begin:, \@@_scope_end:}
-% Scope saving/restoring is done directly with no need to worry about the
-% transformation matrix. General scoping is only for the graphics stack so
-% the lower-cost |gsave|/|grestore| pair are used.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_scope_begin:
- { \tex_special:D { ps:gsave } }
-\cs_new_protected:Npn \@@_scope_end:
- { \tex_special:D { ps:grestore } }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Driver-specific auxiliaries}
-%
-% \begin{macro}[int, EXP]{\@@_absolute_lengths:n}
-% The \texttt{dvips} driver scales all absolute dimensions based
-% on the output resolution selected and any \TeX{} magnification. Thus
-% for any operation involving absolute lengths there is a correction to
-% make. This is based on \texttt{normalscale} from \texttt{special.pro}
-% but using the stack rather than a definition to save the current matrix.
-% \begin{macrocode}
-\cs_new:Npn \@@_absolute_lengths:n #1
- {
- matrix~currentmatrix~
- Resolution~72~div~VResolution~72~div~scale~
- DVImag~dup~scale~
- #1 ~
- setmatrix
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Box operations}
-%
-% \begin{macro}{\@@_box_use_clip:N}
-% Much the same idea as for the PDF mode version but with a slightly
-% different syntax for creating the clip path. To avoid any scaling
-% issues we need the absolute length auxiliary here.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_clip:N #1
- {
- \@@_scope_begin:
- \@@_literal:n
- {
- \@@_absolute_lengths:n
- {
- 0 ~
- \dim_to_decimal_in_bp:n { \box_dp:N #1 } ~
- \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
- \dim_to_decimal_in_bp:n { -\box_ht:N #1 - \box_dp:N #1 } ~
- rectclip
- }
- }
- \hbox_overlap_right:n { \box_use:N #1 }
- \@@_scope_end:
- \skip_horizontal:n { \box_wd:N #1 }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_box_use_rotate:Nn}
-% Rotating using \texttt{dvips} does not require that the box dimensions
-% are altered and has a very convenient built-in operation. Zero rotation
-% must be written as |0| not |-0| so there is a quick test.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
- {
- \@@_scope_begin:
- \@@_literal:n
- {
- \fp_compare:nNnTF {#2} = \c_zero_fp
- { 0 }
- { \fp_eval:n { round ( -#2 , 5 ) } } ~
- rotate
- }
- \box_use:N #1
- \@@_scope_end:
- }
-% \end{macro}
-%
-% \begin{macro}{\@@_box_use_scale:Nnn}
-% The \texttt{dvips} driver once again has a dedicated operation we can
-% use here.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
- {
- \@@_scope_begin:
- \@@_literal:n
- {
- \fp_eval:n { round ( #2 , 5 ) } ~
- \fp_eval:n { round ( #3 , 5 ) } ~
- scale
- }
- \hbox_overlap_right:n { \box_use:N #1 }
- \@@_scope_end:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Color}
-%
-% \begin{variable}{\l_@@_color_current_tl}
-% The current color in driver-dependent format.
-% \begin{macrocode}
-\tl_new:N \l_@@_color_current_tl
-\tl_set:Nn \l_@@_color_current_tl { gray~0 }
-%<*package>
-\AtBeginDocument
- {
- \@ifpackageloaded { color }
- { \tl_set:Nn \l_@@_color_current_tl { \current@color } }
- { }
- }
-%</package>
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[int]{\@@_color_ensure_current:}
-% \begin{macro}[aux]{\@@_color_reset:}
-% Directly set the color using the specials: no optimisation here.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_color_ensure_current:
- {
- \tex_special:D { color~push~\l_@@_color_current_tl }
- \group_insert_after:N \@@_color_reset:
- }
-\cs_new_protected:Npn \@@_color_reset:
- { \tex_special:D { color~pop } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \subsection{Images}
-%
-% \begin{macro}[int]{\@@_image_getbb_eps:n}
-% Simply use the generic function.
-% \begin{macrocode}
-\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_image_include_eps:n}
-% The special syntax is relatively clear here: remember we need PostScript
-% sizes here.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_eps:n #1
- {
- \tex_special:D { PSfile = #1 }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Drawing}
-%
-% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x}
-% Literals with no positioning (using |ps:| each one is positioned but
-% cut off from everything else, so no good for the stepwise approach needed
-% here).
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_literal:n #1
- { \tex_special:D { ps:: ~ #1 } }
-\cs_generate_variant:Nn \@@_draw_literal:n { x }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_draw_begin:, \@@_draw_end:}
-% The |ps::[begin]| special here deals with positioning but allows us to
-% continue on to a matching |ps::[end]|: contrast with |ps:|, which positions
-% but where we can't split material between separate calls. The
-% |@beginspecial|/|@endspecial| pair are from |special.pro| and correct the
-% scale and $y$-axis direction. The reference point at the start of the box
-% is saved (as |l3x|/|l3y|) as it is needed when inserting various items.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_begin:
- {
- \tex_special:D { ps::[begin] }
- \tex_special:D { ps::~save }
- \tex_special:D { ps::~/l3x~currentpoint~/l3y~exch~def~def }
- \tex_special:D { ps::~@beginspecial }
- }
-\cs_new_protected:Npn \@@_draw_end:
- {
- \tex_special:D { ps::~@endspecial }
- \tex_special:D { ps::~restore }
- \tex_special:D { ps::[end] }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_draw_scope_begin:, \@@_draw_scope_end:}
-% Scope here may need to contain saved definitions, so the entire memory
-% rather than just the graphic state has to be sent to the stack.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_scope_begin:
- { \@@_draw_literal:n { save } }
-\cs_new_protected:Npn \@@_draw_scope_end:
- { \@@_draw_literal:n { restore } }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_draw_moveto:nn, \@@_draw_lineto:nn}
-% \begin{macro}[int]{\@@_draw_rectangle:nnnn}
-% \begin{macro}[int]{\@@_draw_curveto:nnnnnn}
-% Path creation operations mainly resolve directly to PostScript primitive
-% steps, with only the need to convert to \texttt{bp}. Notice that
-% \texttt{x}-type expansion is included here to ensure that any variable
-% values are forced to literals before any possible caching. There is
-% no native rectangular path command (without also clipping, filling or
-% stroking), so that task is done using a small amount of PostScript.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_moveto:nn #1#2
- {
- \@@_draw_literal:x
- { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ moveto }
- }
-\cs_new_protected:Npn \@@_draw_lineto:nn #1#2
- {
- \@@_draw_literal:x
- { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ lineto }
- }
-\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4
- {
- \@@_draw_literal:x
- {
- \dim_to_decimal_in_bp:n {#4} ~ \dim_to_decimal_in_bp:n {#3} ~
- \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~
- moveto~dup~0~rlineto~exch~0~exch~rlineto~neg~0~rlineto~clospath
- }
- }
-\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6
- {
- \@@_draw_literal:x
- {
- \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~
- \dim_to_decimal_in_bp:n {#3} ~ \dim_to_decimal_in_bp:n {#4} ~
- \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~
- curveto
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:}
-% \begin{variable}[aux]{\g_@@_draw_eor_bool}
-% The even-odd rule here can be implemented as a simply switch.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_evenodd_rule:
- { \bool_gset_true:N \g_@@_draw_eor_bool }
-\cs_new_protected:Npn \@@_draw_nonzero_rule:
- { \bool_gset_false:N \g_@@_draw_eor_bool }
-\bool_new:N \g_@@_draw_eor_bool
-% \end{macrocode}
-% \end{variable}
-% \end{macro}
-%
-% \begin{macro}[int]
-% {
-% \@@_draw_closepath: ,
-% \@@_draw_stroke: ,
-% \@@_draw_closestroke: ,
-% \@@_draw_fill: ,
-% \@@_draw_fillstroke: ,
-% \@@_draw_clip: ,
-% \@@_draw_discardpath:
-% }
-% \begin{variable}[aux]{\g_@@_draw_clip_bool}
-% Unlike PDF, PostScript doesn't track separate colors for strokes and other
-% elements. It is also desirable to have the |clip| keyword after a stroke or
-% fill. To achieve those outcomes, there is some work to do. For color, if a
-% stroke or fill color is defined it is used for the relevant operation, with
-% a graphic scope inserted as required. That does mean that once such a color
-% is set all further uses inside the same scope have to use scoping: see also
-% the color set up functions. For clipping, the required ordering is achieved
-% using a \TeX{} switch. All of the operations end with a new path instruction
-% as they do not terminate (again in contrast to PDF).
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_closepath:
- { \@@_draw_literal:n { closepath } }
-\cs_new_protected:Npn \@@_draw_stroke:
- {
- \@@_draw_literal:n { currentdict~/l3sc~known~{gsave~l3sc}~if }
- \@@_draw_literal:n { stroke }
- \@@_draw_literal:n { currentdict~/l3sc~known~{grestore}~if }
- \bool_if:NT \g_@@_draw_clip_bool
- {
- \@@_draw_literal:x
- {
- \bool_if:NT \g_@@_draw_eor_bool { eo }
- clip
- }
- }
- \@@_draw_literal:n { newpath }
- \bool_gset_false:N \g_@@_draw_clip_bool
- }
-\cs_new_protected:Npn \@@_draw_closestroke:
- {
- \@@_draw_closepath:
- \@@_draw_stroke:
- }
-\cs_new_protected:Npn \@@_draw_fill:
- {
- \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
- \@@_draw_literal:x
- {
- \bool_if:NT \g_@@_draw_eor_bool { eo }
- fill
- }
- \@@_draw_literal:n { currentdict~/l3fc~known~{grestore}~if }
- \bool_if:NT \g_@@_draw_clip_bool
- {
- \@@_draw_literal:x
- {
- \bool_if:NT \g_@@_draw_eor_bool { eo }
- clip
- }
- }
- \@@_draw_literal:n { newpath }
- \bool_gset_false:N \g_@@_draw_clip_bool
- }
-\cs_new_protected:Npn \@@_draw_fillstroke:
- {
- \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
- \@@_draw_literal:x
- {
- \bool_if:NT \g_@@_draw_eor_bool { eo }
- fill
- }
- \@@_draw_literal:n { currentdict~/l3fc~known~{grestore}~if }
- \@@_draw_literal:n { currentdict~/l3sc~known~{gsave~l3sc}~if }
- \@@_draw_literal:n { stroke }
- \@@_draw_literal:n { currentdict~/l3sc~known~{grestore}~if }
- \bool_if:NT \g_@@_draw_clip_bool
- {
- \@@_draw_literal:x
- {
- \bool_if:NT \g_@@_draw_eor_bool { eo }
- clip
- }
- }
- \@@_draw_literal:n { newpath }
- \bool_gset_false:N \g_@@_draw_clip_bool
- }
-\cs_new_protected:Npn \@@_draw_clip:
- { \bool_gset_true:N \g_@@_draw_clip_bool }
-\bool_new:N \g_@@_draw_clip_bool
-\cs_new_protected:Npn \@@_draw_discardpath:
- {
- \bool_if:NT \g_@@_draw_clip_bool
- {
- \@@_draw_literal:x
- {
- \bool_if:NT \g_@@_draw_eor_bool { eo }
- clip
- }
- }
- \@@_draw_literal:n { newpath }
- \bool_gset_false:N \g_@@_draw_clip_bool
- }
-% \end{macrocode}
-% \end{variable}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_draw_dash:nn}
-% \begin{macro}[aux]{\@@_draw_dash:n}
-% \begin{macro}[int]{\@@_draw_linewidth:n}
-% \begin{macro}[int]{\@@_draw_miterlimit:n}
-% \begin{macro}[int]
-% {
-% \@@_draw_cap_butt:, \@@_draw_cap_round:, \@@_draw_cap_rectangle:,
-% \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel:
-% }
-% Converting paths to output is again a case of mapping directly to
-% PostScript operations.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_dash:nn #1#2
- {
- \@@_draw_literal:x
- {
- [ ~
- \clist_map_function:nN {#1} \@@_draw_dash:n
- ] ~
- \dim_to_decimal_in_bp:n {#2} ~ setdash
- }
- }
-\cs_new:Npn \@@_draw_dash:n #1
- { \dim_to_decimal_in_bp:n {#1} ~ }
-\cs_new_protected:Npn \@@_draw_linewidth:n #1
- {
- \@@_draw_literal:x
- { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth }
- }
-\cs_new_protected:Npn \@@_draw_miterlimit:n #1
- { \@@_draw_literal:x { \fp_eval:n {#1} ~ setmiterlimit } }
-\cs_new_protected:Npn \@@_draw_cap_butt:
- { \@@_draw_literal:n { 0 ~ setlinecap } }
-\cs_new_protected:Npn \@@_draw_cap_round:
- { \@@_draw_literal:n { 1 ~ setlinecap } }
-\cs_new_protected:Npn \@@_draw_cap_rectangle:
- { \@@_draw_literal:n { 2 ~ setlinecap } }
-\cs_new_protected:Npn \@@_draw_join_miter:
- { \@@_draw_literal:n { 0 ~ setlinejoin } }
-\cs_new_protected:Npn \@@_draw_join_round:
- { \@@_draw_literal:n { 1 ~ setlinejoin } }
-\cs_new_protected:Npn \@@_draw_join_bevel:
- { \@@_draw_literal:n { 2 ~ setlinejoin } }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[aux]{\_@@_draw_color_reset:}
-% \begin{macro}[int]
-% {
-% \@@_draw_color_cmyk:nnnn ,
-% \@@_draw_color_cmyk_fill:nnnn ,
-% \@@_draw_color_cmyk_stroke:nnnn
-% }
-% \begin{macro}[int]
-% {
-% \@@_draw_color_gray:n ,
-% \@@_draw_color_gray_fill:n ,
-% \@@_draw_color_gray_stroke:n
-% }
-% \begin{macro}[int]
-% {
-% \@@_draw_color_rgb:nnn ,
-% \@@_draw_color_rgb_fill:nnn ,
-% \@@_draw_color_rgb_stroke:nnn
-% }
-% To allow color to be defined for strokes and fills separately and to
-% respect scoping, the data needs to be stored at the PostScript level.
-% We cannot undefine (local) fill/stroke colors once set up but we can
-% set them blank to improve performance slightly.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_color_reset:
- {
- \@@_draw_literal:n { currentdic~/l3fc~known~{ /l3fc~ { } ~def }~if }
- \@@_draw_literal:n { currentdic~/l3sc~known~{ /l3sc~ { } ~def }~if }
- }
-\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn #1#2#3#4
- {
- \@@_draw_literal:x
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- setcmykcolor ~
- }
- \@@_draw_color_reset:
- }
-\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn #1#2#3#4
- {
- \@@_draw_literal:x
- {
- /l3fc ~
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- setcmykcolor
- } ~
- def
- }
- }
-\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
- {
- \__driver_draw_literal:x
- {
- /l3sc ~
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- setcmykcolor
- } ~
- def
- }
- }
-\cs_new_protected:Npn \@@_draw_color_gray:n #1
- {
- \@@_draw_literal:x { fp_eval:n {#1} ~ setgray }
- \@@_draw_color_reset:
- }
-\cs_new_protected:Npn \@@_draw_color_gray_fill:n #1
- { \@@_draw_literal:x { /l3fc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
-\cs_new_protected:Npn \@@_draw_color_gray_stroke:n #1
- { \@@_draw_literal:x { /l3sc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
-\cs_new_protected:Npn \@@_draw_color_rgb:nnn #1#2#3
- {
- \@@_draw_literal:x
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
- setrgbcolor
- }
- \@@_draw_color_reset:
- }
-\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn #1#2#3
- {
- \@@_draw_literal:x
- {
- /l3fc ~
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
- setrgbcolor
- } ~
- def
- }
- }
-\cs_new_protected:Npn \@@_draw_color_rgb_stroke:nnn #1#2#3
- {
- \@@_draw_literal:x
- {
- /l3sc ~
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
- setrgbcolor
- } ~
- def
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_draw_transformcm:nnnnnn}
-% The first four arguments here are floats (the affine matrix), the last
-% two are a displacement vector. Once again, force evaluation to allow for
-% caching.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_transformcm:nnnnnn #1#2#3#4#5#6
- {
- \@@_draw_literal:x
- {
- [
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~
- ] ~
- concat
- }
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_draw_hbox:Nnnnnnn}
-% Inside a picture |@beginspecial|/|@endspecial| are active, which is
-% normally a good thing but means that the position and scaling will be off
-% if the box is inserted directly. Instead, we need to reverse the effect of
-% the (normally desirable) shift/scaling within the box. That requires
-% knowing where the reference point for the drawing is: saved as |l3x|/|l3y|
-% at the start of the picture. Transformation here is relative to the
-% drawing origin so has to be done purely in driver code not using \TeX{}
-% offsets.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_hbox:Nnnnnnn #1#2#3#4#5#6#7
- {
- \@@_scope_begin:
- \tex_special:D { ps::[end] }
- \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5} {#6} {#7}
- \tex_special:D { ps::~72~Resolution~div~72~VResolution~div~neg~scale }
- \tex_special:D { ps::~magscale~{1~DVImag~div~dup~scale}~if }
- \tex_special:D { ps::~l3x~neg~l3y~neg~translate }
- \group_begin:
- \box_set_wd:Nn #1 { 0pt }
- \box_set_ht:Nn #1 { 0pt }
- \box_set_dp:Nn #1 { 0pt }
- \box_use:N #1
- \group_end:
- \tex_special:D { ps::[begin] }
- \@@_scope_end:
- }
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macrocode}
-%</dvips>
-% \end{macrocode}
-%
% \subsection{\texttt{dvisvgm} driver}
%
% \begin{macrocode}
@@ -2253,36 +2373,37 @@
% \end{macrocode}
% \end{macro}
%
-% \subsubsection{Color}
+% \subsection{Images}
%
-% \begin{variable}{\l_@@_color_current_tl}
-% The current color in driver-dependent format: the same as for
-% \texttt{dvips}.
+% \begin{macro}[int]{\@@_image_getbb_png:n, \@@_image_getbb_jpg:n}
+% These can be included by extracting the bounding box data.
% \begin{macrocode}
-\tl_new:N \l_@@_color_current_tl
-\tl_set:Nn \l_@@_color_current_tl { gray~0 }
-%<*package>
-\AtBeginDocument
- {
- \@ifpackageloaded { color }
- { \tl_set:Nn \l_@@_color_current_tl { \current@color } }
- { }
- }
-%</package>
+\cs_new_eq:NN \@@_image_getbb_png:n \__image_extract_bb:n
+\cs_new_eq:NN \@@_image_getbb_jpg:n \__image_extract_bb:n
% \end{macrocode}
-% \end{variable}
+% \end{macro}
%
-% \begin{macro}[int]{\@@_color_ensure_current:}
-% \begin{macro}[aux]{\@@_color_reset:}
-% Directly set the color: same as \texttt{dvips}.
+% \begin{macro}[int]{\@@_image_include_png:n, \@@_image_include_jpg:n}
+% \begin{macro}[aux]{\@@_image_include_bitmap_quote:w}
+% The driver here has built-in support for basic image inclusion (see
+% \texttt{dvisvgm.def} for a more complex approach, needed if clipping,
+% \emph{etc.}, is covered at the image driver level). The only issue is
+% that |#1| must be quote-corrected. The \texttt{dvisvgm:img} operation
+% quotes the file name, but if it is already quoted (contains spaces)
+% then we have an issue: we simply strip off any quotes as a result.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_color_ensure_current:
+\cs_new_protected:Npn \@@_image_include_png:n #1
{
- \tex_special:D { color~push~\l_@@_color_current_tl }
- \group_insert_after:N \@@_color_reset:
+ \tex_special:D
+ {
+ dvisvgm:img~
+ \dim_to_decimal:n { \l__image_ury_dim } ~
+ \dim_to_decimal:n { \l__image_ury_dim } ~
+ \@@_image_include_bitmap_quote:w #1 " " \q_stop
+ }
}
-\cs_new_protected:Npn \@@_color_reset:
- { \tex_special:D { color~pop } }
+\cs_new_eq:NN \@@_image_include_jpg:n \@@_image_include_png:n
+\cs_new:Npn \@@_image_include_bitmap_quote:w #1 " #2 " #3 \q_stop { #1#2 }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -2361,7 +2482,7 @@
% Once again, some work is needed to get path constructs correct. Rather
% then write the values as they are given, the entire path needs to be
% collected up before being output in one go. For that we use a dedicated
-% storage routine, which will add spaces as required. Since paths should
+% storage routine, which adds spaces as required. Since paths should
% be fully expanded there is no need to worry about the internal
% \texttt{x}-type expansion.
% \begin{macrocode}