[latex3-commits] [l3svn] 01/02: Move dvips driver code to top of source file

noreply at latex-project.org noreply at latex-project.org
Wed Jun 14 16:45:17 CEST 2017


This is an automated email from the git hooks/post-receive script.

joseph pushed a commit to branch master
in repository l3svn.

commit 09b6f9907c6d4c1463aa3123b05690d0005eb88f
Author: Joseph Wright <joseph.wright at morningstar2.co.uk>
Date:   Wed Jun 14 09:52:51 2017 +0100

    Move dvips driver code to top of source file
    
    This is going to help with some code sharing.
---
 l3kernel/l3drivers.dtx | 2270 ++++++++++++++++++++++++------------------------
 1 file changed, 1135 insertions(+), 1135 deletions(-)

diff --git a/l3kernel/l3drivers.dtx b/l3kernel/l3drivers.dtx
index 6fe35dc..36e6f26 100644
--- a/l3kernel/l3drivers.dtx
+++ b/l3kernel/l3drivers.dtx
@@ -487,66 +487,63 @@
 %</package>
 %    \end{macrocode}
 %
-% \subsection{\texttt{pdfmode} driver}
+% \subsection{\texttt{dvips} driver}
 %
 %    \begin{macrocode}
-%<*pdfmode>
+%<*dvips>
 %    \end{macrocode}
 %
-% The direct PDF driver covers both \pdfTeX{} and \LuaTeX{}. The latter
-% renames/restructures the driver primitives but this can be handled
-% at one level of abstraction. As such, we avoid using two separate drivers
-% for this material at the cost of some \texttt{x}-type definitions to get
-% everything expanded up-front.
-%
 % \subsubsection{Basics}
 %
 % \begin{macro}[int]{\@@_literal:n}
-%   This is equivalent to \verb|\special{pdf:}| but the engine can
-%   track it. Without the \texttt{direct} keyword everything is kept in
-%   sync: the transformation matrix is set to the current point automatically.
-%   Note that this is still inside the text (\texttt{BT} \dots \texttt{ET}
-%   block).
+%   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:Npx \@@_literal:n #1
+\cs_new_protected:Npn \@@_literal:n #1
   {
-    \cs_if_exist:NTF \luatex_pdfextension:D
-      { \luatex_pdfextension:D literal }
-      { \pdftex_pdfliteral:D }
-        {#1}
+    \tex_special:D
+      {
+        ps:
+          currentpoint~
+          currentpoint~translate~
+          #1 ~
+          neg~exch~neg~exch~translate
+      }
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
-%  Higher-level interfaces for saving and restoring the graphic state.
+% \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:Npx \@@_scope_begin:
-  {
-    \cs_if_exist:NTF \luatex_pdfextension:D
-      { \luatex_pdfextension:D save \scan_stop: }
-      { \pdftex_pdfsave:D }
-  }
-\cs_new_protected:Npx \@@_scope_end:
-  {
-    \cs_if_exist:NTF \luatex_pdfextension:D
-      { \luatex_pdfextension:D restore \scan_stop: }
-      { \pdftex_pdfrestore:D }
-  }
+\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}
 %
-% \begin{macro}[int]{\@@_matrix:n}
-%   Here the appropriate function is set up to insert an affine matrix
-%   into the PDF. With \pdfTeX{} and \LuaTeX{} in direct PDF output mode there
-%   is a primitive for this, which only needs the rotation/scaling/skew part.
+% \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_protected:Npx \@@_matrix:n #1
+\cs_new:Npn \@@_absolute_lengths:n #1
   {
-    \cs_if_exist:NTF \luatex_pdfextension:D
-      { \luatex_pdfextension:D setmatrix }
-      { \pdftex_pdfsetmatrix:D }
-        {#1}
+     matrix~currentmatrix~
+     Resolution~72~div~VResolution~72~div~scale~
+     DVImag~dup~scale~
+     #1 ~
+     setmatrix
   }
 %    \end{macrocode}
 % \end{macro}
@@ -554,24 +551,23 @@
 % \subsubsection{Box operations}
 %
 % \begin{macro}{\@@_box_use_clip:N}
-%   The general method is to save the current location, define a clipping path
-%   equivalent to the bounding box, then insert the content at the current
-%   position and in a zero width box. The \enquote{real} width is then made up
-%   using a horizontal skip before tidying up. There are other approaches that
-%   can be taken (for example using XForm objects), but the logic here shares
-%   as much code as possible and uses the same conversions (and so same
-%   rounding errors) in all cases.
+%   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
       {
-        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 } ~
-        re~W~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:
@@ -580,57 +576,38 @@
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_box_use_rotate:Nn}
-% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
-%   Rotations are set using an affine transformation matrix which therefore
-%   requires sine/cosine values not the angle itself. We store the rounded
-%   values to avoid rounding twice. There are also a couple of comparisons to
-%   ensure that |-0| is not written to the output, as this avoids any issues
-%   with problematic display programs.  Note that numbers are compared to~$0$
-%   after rounding.
+% \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:
-    \box_set_wd:Nn #1 \c_zero_dim
-    \fp_set:Nn \l_@@_cos_fp { round ( cosd ( #2 ) , 5 ) }
-    \fp_compare:nNnT \l_@@_cos_fp = \c_zero_fp
-      { \fp_zero:N \l_@@_cos_fp }
-    \fp_set:Nn \l_@@_sin_fp { round ( sind ( #2 ) , 5 ) }
-    \@@_matrix:n
+    \@@_literal:n
       {
-        \fp_use:N \l_@@_cos_fp \c_space_tl
-        \fp_compare:nNnTF \l_@@_sin_fp = \c_zero_fp
-          { 0~0 }
-          {
-            \fp_use:N \l_@@_sin_fp
-            \c_space_tl
-            \fp_eval:n { -\l_@@_sin_fp }
-          }
-        \c_space_tl
-        \fp_use:N \l_@@_cos_fp
+        \fp_compare:nNnTF {#2} = \c_zero_fp
+          { 0 }
+          { \fp_eval:n { round ( -#2 , 5 ) } } ~
+        rotate
       }
    \box_use:N #1
    \@@_scope_end:
   }
-\fp_new:N \l_@@_cos_fp
-\fp_new:N \l_@@_sin_fp
-%    \end{macrocode}
-% \end{variable}
 % \end{macro}
 %
 % \begin{macro}{\@@_box_use_scale:Nnn}
-%   The same idea as for rotation but without the complexity of signs and
-%   cosines.
+%   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:
-    \@@_matrix:n
+    \@@_literal:n
       {
         \fp_eval:n { round ( #2 , 5 ) } ~
-        0~0~
-        \fp_eval:n { round ( #3 , 5 ) }
+        \fp_eval:n { round ( #3 , 5 ) } ~
+        scale
       }
     \hbox_overlap_right:n { \box_use:N #1 }
     \@@_scope_end:
@@ -641,11 +618,10 @@
 % \subsubsection{Color}
 %
 % \begin{variable}{\l_@@_color_current_tl}
-%   The current color in driver-dependent format: pick up the package-mode
-%   data if available.
+%   The current color in driver-dependent format.
 %    \begin{macrocode}
 \tl_new:N \l_@@_color_current_tl
-\tl_set:Nn \l_@@_color_current_tl { 0~g~0~G }
+\tl_set:Nn \l_@@_color_current_tl { gray~0 }
 %<*package>
 \AtBeginDocument
   {
@@ -657,1154 +633,1248 @@
 %    \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.
+%   Directly set the color using the specials: no optimisation here.
 %    \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_new_protected:Npn \@@_color_ensure_current:
   {
-    \cs_if_exist:NTF \luatex_pdfextension:D
-      { \luatex_pdfextension:D colorstack }
-      { \pdftex_pdfcolorstack:D }
-        \exp_not:N \l_@@_color_stack_int pop \scan_stop:
+    \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{variable}{\l_@@_image_attr_tl}
-%   In PDF mode, additional attributes of an image (such as page number) are
-%   needed both to obtain the bounding box and when inserting the image: this
-%   occurs as the image dictionary approach means they are read as part of
-%   the bounding box operation. As such, it is easier to track additional
-%   attributes using a dedicated |tl| rather than build up the same data
-%   twice.
+% \begin{macro}[int]{\@@_image_getbb_eps:n}
+%   Simply use the generic function.
 %    \begin{macrocode}
-\tl_new:N \l_@@_image_attr_tl
+\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
 %    \end{macrocode}
-% \end{variable}
+% \end{macro}
 %
-% \begin{macro}[int]
-%   {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n}
-% \begin{macro}[aux]
-%   {\@@_image_getbb_auxi:n, \@@_image_getbb_auxii:n}
-%   Getting the bounding box here requires us to box up the image and
-%   measure it. To deal with the difference in feature support in bitmap
-%   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.
+% \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_getbb_jpg:n #1
+\cs_new_protected:Npn \@@_image_include_eps:n #1
   {
-    \int_zero:N \l__image_page_int
-    \tl_clear:N \l__image_pagebox_tl
-    \tl_set:Nx \l_@@_image_attr_tl
-      {
-        \bool_if:NT \l__image_interpolate_bool
-          { :I }
-      }
-    \tl_clear:N \l_@@_image_attr_tl
-    \@@_image_getbb_auxi:n {#1}
+    \tex_special:D { PSfile = #1 }
   }
-\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
-\cs_new_protected:Npn \@@_image_getbb_pdf:n #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:
   {
-    \bool_set_false:N \l__image_interpolate_bool
-    \tl_set:Nx \l_@@_image_attr_tl
-      {
-        : \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_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_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 will always start 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 } }
-      \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_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 _urx_dim }
-      { \l__image_urx_dim }
-    \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _ury_dim }
-      { \l__image_ury_dim }
+    \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 }
   }
-%    \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]
-%   {\@@_image_include_jpg:n, \@@_image_include_pdf:n, \@@_image_include_png:n}
-%   Images are already loaded for the measurement part of the code, so
-%   inclusion is straight-forward, with only any attributes to worry about. The
-%   latter carry through from determination of the bounding box.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_jpg:n #1
+\cs_new_protected:Npn \@@_draw_end:
   {
-    \pdftex_pdfrefximage:D
-      \int_use:c { c__image_ #1 \l_@@_image_attr_tl _int }
+    \tex_special:D { ps::~@endspecial }
+    \tex_special:D { ps::~restore }
+    \tex_special:D { ps::[end] }
   }
-\cs_new_eq:NN \@@_image_include_pdf:n \@@_image_include_jpg:n
-\cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n
-%    \end{macrocode}
-% \end{macro}
-%
-%    \begin{macrocode}
-%</pdfmode>
-%    \end{macrocode}
-%
-% \subsection{\texttt{dvipdfmx} driver}
-%
-%    \begin{macrocode}
-%<*dvipdfmx|xdvipdfmx>
-%    \end{macrocode}
-%
-% The \texttt{dvipdfmx} shares code with the PDF mode one (using the common
-% section to this file) but also with \texttt{xdvipdfmx}. The latter is close
-% to identical to \texttt{dvipdfmx} and so all of the code here is extracted
-% for both drivers, with some \texttt{clean up} for \texttt{xdvipdfmx} as
-% required.
-%
-% \subsubsection{Basics}
-%
-% \begin{macro}[int]{\@@_literal:n}
-%   Equivalent to \texttt{pdf:content} but favored as the link to
-%   the \pdfTeX{} primitive approach is clearer. Some higher-level operations
-%   use |\tex_special:D| directly: see the later comments on where this is
-%   useful.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_literal:n #1
-  { \tex_special:D { pdf:literal~ #1 } }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
-%   Scoping is done using the driver-specific specials.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_scope_begin:
-  { \tex_special:D { x:gsave } }
-\cs_new_protected:Npn \@@_scope_end:
-  { \tex_special:D { x:grestore } }
+% \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}
 %
-% \subsubsection{Box operations}
-%
-% \begin{macro}{\@@_box_use_clip:N}
-%   The code here is idential to that for \texttt{pdfmode}: unlike rotation and
-%   scaling, there is no higher-level support in the driver for clipping.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_clip:N #1
+% \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
   {
-    \@@_scope_begin:
-    \@@_literal: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 } ~
-        re~W~n
-      }
-    \hbox_overlap_right:n { \box_use:N #1 }
-    \@@_scope_end:
-    \skip_horizontal:n { \box_wd:N #1 }
+    \@@_draw_literal:x
+      { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ moveto }
   }
-%    \end{macrocode}
-% \end{macro}
-%
-% \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
-%   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
-%   \texttt{dvips}, zero rotation is written as |0| not |-0|.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
+\cs_new_protected:Npn \@@_draw_lineto:nn #1#2
   {
-    \@@_scope_begin:
-    \tex_special:D
-      {
-        x:rotate~
-        \fp_compare:nNnTF {#2} = \c_zero_fp
-          { 0 }
-          { \fp_eval:n { round ( #2 , 5 ) } }
+    \@@_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
       }
-    \box_use:N #1
-    \@@_scope_end:
   }
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_box_use_scale:Nnn}
-%   Much the same idea for scaling: use the higher-level driver operation to allow
-%   for box content.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
+\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6
   {
-    \@@_scope_begin:
-    \tex_special:D
+    \@@_draw_literal:x
       {
-        x:scale~
-        \fp_eval:n { round ( #2 , 5 ) } ~
-        \fp_eval:n { round ( #3 , 5 ) }
+        \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
       }
-    \hbox_overlap_right:n { \box_use:N #1 }
-    \@@_scope_end:
-  }
+ }
 %    \end{macrocode}
 % \end{macro}
+% \end{macro}
+% \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 at color } }
-      { }
-  }
-%</package>
+% \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}
-%
-% \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]
 %   {
-%     \@@_image_getbb_eps:n, \@@_image_getbb_jpg:n,
-%     \@@_image_getbb_pdf:n, \@@_image_getbb_png:n
+%     \@@_draw_closepath:   ,
+%     \@@_draw_stroke:      ,
+%     \@@_draw_closestroke: ,
+%     \@@_draw_fill:        ,
+%     \@@_draw_fillstroke:  ,
+%     \@@_draw_clip:        ,
+%     \@@_draw_discardpath:
 %   }
-%   Simply use the generic functions: only for \texttt{dvipdfmx} in the
-%   extraction cases.
-%    \begin{macrocode}
-\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
-%<*dvipdfmx>
-\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
+% \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:
   {
-    \bool_set_false:N \l__image_interpolate_tl
-    \__image_extract_bb:n {#1}
+    \@@_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
   }
-%</dvipdfmx>
-%    \end{macrocode}
-% \end{macro}
-%
-% \begin{variable}[aux]{\g_@@_image_int}
-%   Used to track the object number associated with each image.
-%    \begin{macrocode}
-\int_new:N \g_@@_image_int
-%    \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[int]
-%   {
-%     \@@_image_include_eps:n, \@@_image_include_jpg:n,
-%     \@@_image_include_pdf:n, \@@_image_include_png:n
-%   }
-%  \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. 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
+\cs_new_protected:Npn \@@_draw_closestroke:
   {
-    \tex_special:D { PSfile = #1 }
+    \@@_draw_closepath:
+    \@@_draw_stroke:
   }
-\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_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
-%   only once and refer to them. To allow that, track the nature of each
-%   image: much the same as for the direct PDF mode case.
-%    \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_auxi:nn #1#2
+\cs_new_protected:Npn \@@_draw_fill:
   {
-    \@@_image_include_auxii:xnn
+    \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
+    \@@_draw_literal:x
       {
-        \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 }
-        \bool_if:NT \l__image_interpolate_bool
-           { :I }
+        \bool_if:NT \g_@@_draw_eor_bool { eo }
+        fill
       }
-      {#1} {#2}
+    \@@_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 \@@_image_include_auxii:nnn #1#2#3
+\cs_new_protected:Npn \@@_draw_fillstroke:
   {
-    \int_if_exist:cTF { c__image_ #2#1 _int }
+    \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
+    \@@_draw_literal:x
       {
-        \tex_special:D
-          { pdf:usexobj~@image \int_use:c { c__image_ #2#1 _int } }
+        \bool_if:NT \g_@@_draw_eor_bool { eo }
+        fill
       }
-      { \@@_image_include_auxiii:nn {#2} {#1} {#3} }
+    \@@_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_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
+\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:
   {
-    \int_gincr:N \g_@@_image_int
-    \int_const:cn { c__image_ #1#2 _int } { \g_@@_image_int }
-    \tex_special:D
+    \bool_if:NT \g_@@_draw_clip_bool
       {
-        pdf:#3~
-        @image \int_use:c { c__image_ #1#2 _int }
-        \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
+        \@@_draw_literal:x
           {
-            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
+            \bool_if:NT \g_@@_draw_eor_bool { eo }
+            clip
           }
-        (#1)
-        \bool_if:NT \l__image_interpolate_bool
-          { <</Interpolate~true>> }
       }
+    \@@_draw_literal:n { newpath }
+    \bool_gset_false:N \g_@@_draw_clip_bool
   }
 %    \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+% \end{variable}
 % \end{macro}
 %
-%    \begin{macrocode}
-%</dvipdfmx|xdvipdfmx>
-%    \end{macrocode}
-%
-% \subsection{\texttt{xdvipdfmx} driver}
-%
-%    \begin{macrocode}
-%<*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
+% \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
   {
-    \@ifpackageloaded { color }
+    \@@_draw_literal:x
       {
-        \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 at color [ ] \q_stop
+        [ ~
+          \clist_map_function:nN {#1} \@@_draw_dash:n
+        ] ~
+        \dim_to_decimal_in_bp:n {#2} ~ setdash
       }
-      { }
   }
-%</package>
+\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}
 %
-% \subsection{Images}
-%
+% \begin{macro}[aux]{\_@@_draw_color_reset:}
 % \begin{macro}[int]
-%   {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n}
-% \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 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
+%   {
+%     \@@_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:
   {
-    \int_zero:N \l__image_page_int
-    \@@_image_getbb_auxi:nN {#1} \xetex_picfile:D
+    \@@_draw_literal:n { currentdic~/l3fc~known~{ /l3fc~ { } ~def }~if }
+    \@@_draw_literal:n { currentdic~/l3sc~known~{ /l3sc~ { } ~def }~if }
   }
-\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 }
-\cs_new_protected:Npn \@@_image_getbb_auxi:nN #1#2
+\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn #1#2#3#4
   {
-    \int_compare:nNnTF \l__image_page_int > 1
-      { \@@_image_getbb_auxii:VnN \l__image_page_int {#1} #2  }
-      { \@@_image_getbb_auxiii:nNnn {#1} #2 }
+    \@@_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 \@@_image_getbb_auxii:nnN #1#2#3
-  { \@@_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
+\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn #1#2#3#4
   {
-    \tl_if_empty:NTF \l__image_pagebox_tl
-      { \@@_image_getbb_auxiv:VnNnn \l__image_pagebox_tl }
-      { \@@_image_getbb_auxv: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 \@@_image_getbb_auxiv:nnNnn #1#2#3#4#5
+\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
   {
-    \use:x
+    \__driver_draw_literal:x
       {
-        \@@_image_getbb_auxv:nNnn {#2} #3 { : #1 #4 }
-          { #5 ~ \@@_image_getbb_pagebox:w #1 }
+        /l3sc ~
+          {
+            \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+            \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+            setcmykcolor
+          } ~
+        def
       }
   }
-\cs_generate_variant:Nn \@@_image_getbb_auxiv:nnNnn { V }
-\cs_new_protected:Npn \@@_image_getbb_auxv:nNnn #1#2#3#4
+\cs_new_protected:Npn \@@_draw_color_gray:n #1
   {
-    \dim_zero:N \l__image_llx_dim
-    \dim_zero:N \l__image_lly_dim
-    \dim_if_exist:cTF { c__image_ #1#3 _urx_dim }
+    \@@_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
       {
-        \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 }
+        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
+        setrgbcolor
       }
-      { \@@_image_getbb_auxvi:nNnn {#1} #2 {#3} {#4} }
+    \@@_draw_color_reset:
   }
-\cs_new_protected:Npn \@@_image_getbb_auxvi:nNnn #1#2#3#4
+\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn #1#2#3
   {
-    \hbox_set:Nn \l__image_tmp_box { #2 #1 ~ #4 }
-    \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 }
+    \@@_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
+      }
   }
-\cs_new:Npn \@@_image_getbb_pagebox:w #1 box {#1}
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 % \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]{\@@_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
+% \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
   {
-    \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
+    \@@_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}
-%</xdvipdfmx>
+%</dvips>
 %    \end{macrocode}
 %
-% \subsection{Drawing commands: \texttt{pdfmode} and \texttt{(x)dvipdfmx}}
-%
-% Both \texttt{pdfmode} and \texttt{(x)dvipdfmx} directly produce PDF output
-% and understand a shared set of specials for drawing commands.
+% \subsection{\texttt{pdfmode} driver}
 %
 %    \begin{macrocode}
-%<*dvipdfmx|pdfmode|xdvipdfmx>
+%<*pdfmode>
 %    \end{macrocode}
 %
-% \subsection{Drawing}
+% The direct PDF driver covers both \pdfTeX{} and \LuaTeX{}. The latter
+% renames/restructures the driver primitives but this can be handled
+% at one level of abstraction. As such, we avoid using two separate drivers
+% for this material at the cost of some \texttt{x}-type definitions to get
+% everything expanded up-front.
 %
-% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x}
-%   Pass data through using a dedicated interface.
-%     \begin{macrocode}
-\cs_new_eq:NN \@@_draw_literal:n \@@_literal:n
-\cs_generate_variant:Nn \@@_draw_literal:n { x }
+% \subsubsection{Basics}
+%
+% \begin{macro}[int]{\@@_literal:n}
+%   This is equivalent to \verb|\special{pdf:}| but the engine can
+%   track it. Without the \texttt{direct} keyword everything is kept in
+%   sync: the transformation matrix is set to the current point automatically.
+%   Note that this is still inside the text (\texttt{BT} \dots \texttt{ET}
+%   block).
+%    \begin{macrocode}
+\cs_new_protected:Npx \@@_literal:n #1
+  {
+    \cs_if_exist:NTF \luatex_pdfextension:D
+      { \luatex_pdfextension:D literal }
+      { \pdftex_pdfliteral:D }
+        {#1}
+  }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_draw_begin:, \@@_draw_end:}
-%   No special requirements here, so simply set up a drawing scope.
-%     \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_begin:
-  { \@@_draw_scope_begin: }
-\cs_new_protected:Npn \@@_draw_end:
-  { \@@_draw_scope_end: }
+% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
+%  Higher-level interfaces for saving and restoring the graphic state.
+%    \begin{macrocode}
+\cs_new_protected:Npx \@@_scope_begin:
+  {
+    \cs_if_exist:NTF \luatex_pdfextension:D
+      { \luatex_pdfextension:D save \scan_stop: }
+      { \pdftex_pdfsave:D }
+  }
+\cs_new_protected:Npx \@@_scope_end:
+  {
+    \cs_if_exist:NTF \luatex_pdfextension:D
+      { \luatex_pdfextension:D restore \scan_stop: }
+      { \pdftex_pdfrestore:D }
+  }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_draw_scope_begin:, \@@_draw_scope_end:}
-%   In contrast to a general scope, a drawing scope is always done using
-%   the PDF operators so is the same for all relevant drivers.
-%     \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_scope_begin:
-  { \@@_draw_literal:n { q } }
-\cs_new_protected:Npn \@@_draw_scope_end:
-  { \@@_draw_literal:n { Q } }
+% \begin{macro}[int]{\@@_matrix:n}
+%   Here the appropriate function is set up to insert an affine matrix
+%   into the PDF. With \pdfTeX{} and \LuaTeX{} in direct PDF output mode there
+%   is a primitive for this, which only needs the rotation/scaling/skew part.
+%    \begin{macrocode}
+\cs_new_protected:Npx \@@_matrix:n #1
+  {
+    \cs_if_exist:NTF \luatex_pdfextension:D
+      { \luatex_pdfextension:D setmatrix }
+      { \pdftex_pdfsetmatrix:D }
+        {#1}
+  }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_draw_moveto:nn, \@@_draw_lineto:nn}
-% \begin{macro}[int]{\@@_draw_curveto:nnnnnn}
-% \begin{macro}[int]{\@@_draw_rectangle:nnnn}
-%   Path creation operations all resolve directly to PDF 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.
-%     \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} ~ m }
-  }
-\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} ~ l }
-  }
-\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} ~
-        c
-      }
- }
-\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4
+% \subsubsection{Box operations}
+%
+% \begin{macro}{\@@_box_use_clip:N}
+%   The general method is to save the current location, define a clipping path
+%   equivalent to the bounding box, then insert the content at the current
+%   position and in a zero width box. The \enquote{real} width is then made up
+%   using a horizontal skip before tidying up. There are other approaches that
+%   can be taken (for example using XForm objects), but the logic here shares
+%   as much code as possible and uses the same conversions (and so same
+%   rounding errors) in all cases.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_clip:N #1
   {
-     \@@_draw_literal:x
+    \@@_scope_begin:
+    \@@_literal:n
       {
-        \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} ~
-        re
+        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 } ~
+        re~W~n
       }
+    \hbox_overlap_right:n { \box_use:N #1 }
+    \@@_scope_end:
+    \skip_horizontal:n { \box_wd:N #1 }
   }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
-% \end{macro}
 %
-% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:}
-% \begin{variable}[int]{\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
+% \begin{macro}[int]{\@@_box_use_rotate:Nn}
+% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
+%   Rotations are set using an affine transformation matrix which therefore
+%   requires sine/cosine values not the angle itself. We store the rounded
+%   values to avoid rounding twice. There are also a couple of comparisons to
+%   ensure that |-0| is not written to the output, as this avoids any issues
+%   with problematic display programs.  Note that numbers are compared to~$0$
+%   after rounding.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
+  {
+    \@@_scope_begin:
+    \box_set_wd:Nn #1 \c_zero_dim
+    \fp_set:Nn \l_@@_cos_fp { round ( cosd ( #2 ) , 5 ) }
+    \fp_compare:nNnT \l_@@_cos_fp = \c_zero_fp
+      { \fp_zero:N \l_@@_cos_fp }
+    \fp_set:Nn \l_@@_sin_fp { round ( sind ( #2 ) , 5 ) }
+    \@@_matrix:n
+      {
+        \fp_use:N \l_@@_cos_fp \c_space_tl
+        \fp_compare:nNnTF \l_@@_sin_fp = \c_zero_fp
+          { 0~0 }
+          {
+            \fp_use:N \l_@@_sin_fp
+            \c_space_tl
+            \fp_eval:n { -\l_@@_sin_fp }
+          }
+        \c_space_tl
+        \fp_use:N \l_@@_cos_fp
+      }
+   \box_use:N #1
+   \@@_scope_end:
+  }
+\fp_new:N \l_@@_cos_fp
+\fp_new:N \l_@@_sin_fp
 %    \end{macrocode}
 % \end{variable}
 % \end{macro}
 %
-% \begin{macro}[int]
-%   {
-%     \@@_draw_closepath:   ,
-%     \@@_draw_stroke:      ,
-%     \@@_draw_closestroke: ,
-%     \@@_draw_fill:        ,
-%     \@@_draw_fillstroke:  ,
-%     \@@_draw_clip:        ,
-%     \@@_draw_discardpath:
-%   }
-%   Converting paths to output is again a case of mapping directly to
-%   PDF operations.
-%     \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_closepath:
-  { \@@_draw_literal:n { h } }
-\cs_new_protected:Npn \@@_draw_stroke:
-  { \@@_draw_literal:n { S } }
-\cs_new_protected:Npn \@@_draw_closestroke:
-  { \@@_draw_literal:n { s } }
-\cs_new_protected:Npn \@@_draw_fill:
-  {
-    \@@_draw_literal:x
-      { f \bool_if:NT \g_@@_draw_eor_bool * }
-  }
-\cs_new_protected:Npn \@@_draw_fillstroke:
+% \begin{macro}{\@@_box_use_scale:Nnn}
+%   The same idea as for rotation but without the complexity of signs and
+%   cosines.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
   {
-    \@@_draw_literal:x
-      { B \bool_if:NT \g_@@_draw_eor_bool * }
+    \@@_scope_begin:
+    \@@_matrix:n
+      {
+        \fp_eval:n { round ( #2 , 5 ) } ~
+        0~0~
+        \fp_eval:n { round ( #3 , 5 ) }
+      }
+    \hbox_overlap_right:n { \box_use:N #1 }
+    \@@_scope_end:
   }
-\cs_new_protected:Npn \@@_draw_clip:
+%    \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
   {
-    \@@_draw_literal:x
-      { W \bool_if:NT \g_@@_draw_eor_bool * }
+    \@ifpackageloaded { color }
+      { \tl_set:Nn \l_@@_color_current_tl { \current at color } }
+      { }
   }
-\cs_new_protected:Npn \@@_draw_discardpath:
-  { \@@_draw_literal:n { n } }
+%</package>
 %    \end{macrocode}
-% \end{macro}
+% \end{variable}
 %
-% \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
-%   PDF operations.
-%     \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_dash:nn #1#2
+% \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:
   {
-    \@@_draw_literal:x
-      {
-        [ ~
-          \clist_map_function:nN {#1} \@@_draw_dash:n
-        ] ~
-        \dim_to_decimal_in_bp:n {#2} ~ d
-      }
+    \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:Npn \@@_draw_dash:n #1
-  { \dim_to_decimal_in_bp:n {#1} ~ }
-\cs_new_protected:Npn \@@_draw_linewidth:n #1
+\cs_new_protected:Npx \@@_color_reset:
   {
-    \@@_draw_literal:x
-      { \dim_to_decimal_in_bp:n {#1} ~ w }
+    \cs_if_exist:NTF \luatex_pdfextension:D
+      { \luatex_pdfextension:D colorstack }
+      { \pdftex_pdfcolorstack:D }
+        \exp_not:N \l_@@_color_stack_int pop \scan_stop:
   }
-\cs_new_protected:Npn \@@_draw_miterlimit:n #1
-  { \@@_draw_literal:x { \fp_eval:n {#1} ~ M } }
-\cs_new_protected:Npn \@@_draw_cap_butt:
-  { \@@_draw_literal:n { 0 ~ J } }
-\cs_new_protected:Npn \@@_draw_cap_round:
-  { \@@_draw_literal:n { 1 ~ J } }
-\cs_new_protected:Npn \@@_draw_cap_rectangle:
-  { \@@_draw_literal:n { 2 ~ J } }
-\cs_new_protected:Npn \@@_draw_join_miter:
-  { \@@_draw_literal:n { 0 ~ j } }
-\cs_new_protected:Npn \@@_draw_join_round:
-  { \@@_draw_literal:n { 1 ~ j } }
-\cs_new_protected:Npn \@@_draw_join_bevel:
-  { \@@_draw_literal:n { 2 ~ j } }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+%
+% \subsection{Images}
+%
+% \begin{variable}{\l_@@_image_attr_tl}
+%   In PDF mode, additional attributes of an image (such as page number) are
+%   needed both to obtain the bounding box and when inserting the image: this
+%   occurs as the image dictionary approach means they are read as part of
+%   the bounding box operation. As such, it is easier to track additional
+%   attributes using a dedicated |tl| rather than build up the same data
+%   twice.
+%    \begin{macrocode}
+\tl_new:N \l_@@_image_attr_tl
+%    \end{macrocode}
+% \end{variable}
 %
 % \begin{macro}[int]
-%   {
-%     \@@_draw_color_cmyk:nnnn        ,
-%     \@@_draw_color_cmyk_fill:nnnn   ,
-%     \@@_draw_color_cmyk_stroke:nnnn
-%   }
-% \begin{macro}[aux]{\@@_draw_color_cmyk_aux:nnnn}
-% \begin{macro}[int]
-%   {
-%     \@@_draw_color_gray:n        ,
-%     \@@_draw_color_gray_fill:n   ,
-%     \@@_draw_color_gray_stroke:n
-%   }
-% \begin{macro}[aux]{\@@_draw_color_gray_aux:n}
-% \begin{macro}[int]
-%   {
-%     \@@_draw_color_rgb:nnn        ,
-%     \@@_draw_color_rgb_fill:nnn   ,
-%     \@@_draw_color_rgb_stroke:nnn
-%   }
-% \begin{macro}[aux]{\@@_draw_color_rgb_aux:nnn}
-%   Yet more fast conversion, all using the FPU to allow for expressions
-%   in numerical input.
-%     \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn #1#2#3#4
+%   {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n}
+% \begin{macro}[aux]
+%   {\@@_image_getbb_auxi:n, \@@_image_getbb_auxii:n}
+%   Getting the bounding box here requires us to box up the image and
+%   measure it. To deal with the difference in feature support in bitmap
+%   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.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
   {
-    \use:x
+    \int_zero:N \l__image_page_int
+    \tl_clear:N \l__image_pagebox_tl
+    \tl_set:Nx \l_@@_image_attr_tl
       {
-        \@@_draw_color_cmyk_aux:nnnn
-          { \fp_eval:n {#1} }
-          { \fp_eval:n {#2} }
-          { \fp_eval:n {#3} }
-          { \fp_eval:n {#4} }
+        \bool_if:NT \l__image_interpolate_bool
+          { :I }
       }
+    \tl_clear:N \l_@@_image_attr_tl
+    \@@_image_getbb_auxi:n {#1}
   }
-\cs_new_protected:Npn \@@_draw_color_cmyk_aux:nnnn #1#2#3#4
-  {
-    \@@_draw_literal:n
-      { #1 ~ #2 ~ #3 ~ #4 ~ k ~ #1 ~ #2 ~ #3 ~ #4 ~ K }
-  }
-\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn #1#2#3#4
+\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
+\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
   {
-    \@@_draw_literal:x
+    \bool_set_false:N \l__image_interpolate_bool
+    \tl_set:Nx \l_@@_image_attr_tl
       {
-        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
-        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
-        k
+        : \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 \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
+\cs_new_protected:Npn \@@_image_getbb_auxi:n #1
   {
-    \@@_draw_literal:x
+    \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 }
       {
-        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
-        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
-        K
+        \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} }
   }
-\cs_new_protected:Npn \@@_draw_color_gray: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 will always start 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
   {
-    \use:x
-      { \@@_draw_color_gray_aux:n { \fp_eval:n {#1} } }
+    \tex_immediate:D \pdftex_pdfximage:D
+      \bool_if:NT \l__image_interpolate_bool
+        { attr ~ { /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_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 _urx_dim }
+      { \l__image_urx_dim }
+    \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _ury_dim }
+      { \l__image_ury_dim }
   }
-\cs_new_protected:Npn \@@_draw_color_gray_aux:n #1
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]
+%   {\@@_image_include_jpg:n, \@@_image_include_pdf:n, \@@_image_include_png:n}
+%   Images are already loaded for the measurement part of the code, so
+%   inclusion is straight-forward, with only any attributes to worry about. The
+%   latter carry through from determination of the bounding box.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_image_include_jpg:n #1
   {
-    \@@_draw_literal:n { #1 ~ g ~ #1 ~ G }
+    \pdftex_pdfrefximage:D
+      \int_use:c { c__image_ #1 \l_@@_image_attr_tl _int }
   }
-\cs_new_protected:Npn \@@_draw_color_gray_fill:n #1
-  { \@@_draw_literal:x { \fp_eval:n {#1} ~ g } }
-\cs_new_protected:Npn \@@_draw_color_gray_stroke:n #1
-  { \@@_draw_literal:x { \fp_eval:n {#1} ~ G } }
-\cs_new_protected:Npn \@@_draw_color_rgb:nnn #1#2#3
+\cs_new_eq:NN \@@_image_include_pdf:n \@@_image_include_jpg:n
+\cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n
+%    \end{macrocode}
+% \end{macro}
+%
+%    \begin{macrocode}
+%</pdfmode>
+%    \end{macrocode}
+%
+% \subsection{\texttt{dvipdfmx} driver}
+%
+%    \begin{macrocode}
+%<*dvipdfmx|xdvipdfmx>
+%    \end{macrocode}
+%
+% The \texttt{dvipdfmx} shares code with the PDF mode one (using the common
+% section to this file) but also with \texttt{xdvipdfmx}. The latter is close
+% to identical to \texttt{dvipdfmx} and so all of the code here is extracted
+% for both drivers, with some \texttt{clean up} for \texttt{xdvipdfmx} as
+% required.
+%
+% \subsubsection{Basics}
+%
+% \begin{macro}[int]{\@@_literal:n}
+%   Equivalent to \texttt{pdf:content} but favored as the link to
+%   the \pdfTeX{} primitive approach is clearer. Some higher-level operations
+%   use |\tex_special:D| directly: see the later comments on where this is
+%   useful.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_literal:n #1
+  { \tex_special:D { pdf:literal~ #1 } }
+%    \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
+%   Scoping is done using the driver-specific specials.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_scope_begin:
+  { \tex_special:D { x:gsave } }
+\cs_new_protected:Npn \@@_scope_end:
+  { \tex_special:D { x:grestore } }
+%    \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Box operations}
+%
+% \begin{macro}{\@@_box_use_clip:N}
+%   The code here is idential to that for \texttt{pdfmode}: unlike rotation and
+%   scaling, there is no higher-level support in the driver for clipping.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_clip:N #1
   {
-    \use:x
+    \@@_scope_begin:
+    \@@_literal:n
       {
-        \@@_draw_color_rgb_aux:nnn
-          { \fp_eval:n {#1} }
-          { \fp_eval:n {#2} }
-          { \fp_eval:n {#3} }
+        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 } ~
+        re~W~n
       }
-  }
-\cs_new_protected:Npn \@@_draw_color_rgb_aux:nnn #1#2#3
-  {
-    \@@_draw_literal:n
-      { #1 ~ #2 ~ #3 ~ rg ~ #1 ~ #2 ~ #3 ~ RG }
-  }
-\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn #1#2#3
-  {
-    \@@_draw_literal:x
-      { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ rg }
-  }
-\cs_new_protected:Npn \@@_draw_color_rgb_stroke:nnn #1#2#3
-  {
-    \@@_draw_literal:x
-      { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ RG }
+    \hbox_overlap_right:n { \box_use:N #1 }
+    \@@_scope_end:
+    \skip_horizontal:n { \box_wd:N #1 }
   }
 %    \end{macrocode}
 % \end{macro}
-% \end{macro}
-% \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
+% \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
+%   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
+%   \texttt{dvips}, zero rotation is written as |0| not |-0|.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
   {
-    \@@_draw_literal:x
+    \@@_scope_begin:
+    \tex_special:D
       {
-        \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} ~
-        cm
+        x:rotate~
+        \fp_compare:nNnTF {#2} = \c_zero_fp
+          { 0 }
+          { \fp_eval:n { round ( #2 , 5 ) } }
       }
+    \box_use:N #1
+    \@@_scope_end:
   }
 %    \end{macrocode}
 % \end{macro}
 %
-% \begin{macro}[int]{\@@_draw_hbox:Nnnnnnn}
-% \begin{variable}[aux]{\l_@@_tmp_box}
-%   Inserting a \TeX{} box transformed to the requested position and using
-%   the current matrix is done using a mixture of \TeX{} and low-level
-%   manipulation. The offset can be handled by \TeX{}, so only any rotation/^^A
-%   skew/scaling component needs to be done using the matrix operation. As this
-%   operation can never be cached, the scope is set directly not using the
-%   \texttt{draw} version.
-%     \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_hbox:Nnnnnnn #1#2#3#4#5#6#7
+% \begin{macro}{\@@_box_use_scale:Nnn}
+%   Much the same idea for scaling: use the higher-level driver operation to allow
+%   for box content.
+%    \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
   {
-    \hbox_set:Nn \l_@@_tmp_box
+    \@@_scope_begin:
+    \tex_special:D
       {
-        \tex_kern:D \__dim_eval:w #6 \__dim_eval_end:
-        \@@_scope_begin:
-        \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5}
-          { 0pt } { 0pt }
-        \box_move_up:nn {#7} { \box_use:N #1 }
-        \@@_scope_end:
+        x:scale~
+        \fp_eval:n { round ( #2 , 5 ) } ~
+        \fp_eval:n { round ( #3 , 5 ) }
       }
-    \box_set_wd:Nn \l_@@_tmp_box { 0pt }
-    \box_set_ht:Nn \l_@@_tmp_box { 0pt }
-    \box_set_dp:Nn \l_@@_tmp_box { 0pt }
-    \box_use:N \l_@@_tmp_box
+    \hbox_overlap_right:n { \box_use:N #1 }
+    \@@_scope_end:
   }
-\box_new:N \l_@@_tmp_box
 %    \end{macrocode}
-% \end{variable}
 % \end{macro}
 %
+% \subsubsection{Color}
+%
+% \begin{variable}{\l_@@_color_current_tl}
+%   The current color in driver-dependent format.
 %    \begin{macrocode}
-%</dvipdfmx|pdfmode|xdvipdfmx>
+\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 at color } }
+      { }
+  }
+%</package>
 %    \end{macrocode}
+% \end{variable}
 %
-% \subsection{\texttt{dvips} driver}
-%
+% \begin{macro}[int]{\@@_color_ensure_current:}
+% \begin{macro}[aux]{\@@_color_reset:}
+%   Directly set the color using the specials with optimisation support.
 %    \begin{macrocode}
-%<*dvips>
+\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}
 %
-% \subsubsection{Basics}
+% \subsection{Images}
 %
-% \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{macro}[int]
+%   {
+%     \@@_image_getbb_eps:n, \@@_image_getbb_jpg:n,
+%     \@@_image_getbb_pdf:n, \@@_image_getbb_png:n
+%   }
+%   Simply use the generic functions: only for \texttt{dvipdfmx} in the
+%   extraction cases.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_literal:n #1
+\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
+%<*dvipdfmx>
+\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
   {
-    \tex_special:D
-      {
-        ps:
-          currentpoint~
-          currentpoint~translate~
-          #1 ~
-          neg~exch~neg~exch~translate
-      }
+    \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
+    \__image_extract_bb:n {#1}
   }
+%</dvipdfmx>
 %    \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{variable}[aux]{\g_@@_image_int}
+%   Used to track the object number associated with each image.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_scope_begin:
-  { \tex_special:D { ps:gsave } }
-\cs_new_protected:Npn \@@_scope_end:
-  { \tex_special:D { ps:grestore } }
+\int_new:N \g_@@_image_int
 %    \end{macrocode}
-% \end{macro}
-%
-% \subsection{Driver-specific auxiliaries}
+% \end{variable}
 %
-% \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{macro}[int]
+%   {
+%     \@@_image_include_eps:n, \@@_image_include_jpg:n,
+%     \@@_image_include_pdf:n, \@@_image_include_png:n
+%   }
+%  \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. 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:Npn \@@_absolute_lengths:n #1
+\cs_new_protected:Npn \@@_image_include_eps:n #1
   {
-     matrix~currentmatrix~
-     Resolution~72~div~VResolution~72~div~scale~
-     DVImag~dup~scale~
-     #1 ~
-     setmatrix
+    \tex_special:D { PSfile = #1 }
   }
+\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_jpg:n
+%<*dvipdfmx>
+\cs_new_protected:Npn \@@_image_include_pdf:n #1
+  { \@@_image_include_auxi:nn {#1} { epdf } }
+%</dvipdfmx>
 %    \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.
+%   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
+%   only once and refer to them. To allow that, track the nature of each
+%   image: much the same as for the direct PDF mode case.
 %    \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_clip:N #1
+\cs_new_protected:Npn \@@_image_include_auxi:nn #1#2
   {
-    \@@_scope_begin:
-    \@@_literal:n
+    \@@_image_include_auxii:xnn
       {
-        \@@_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
-          }
+        \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 }
+        \bool_if:NT \l__image_interpolate_bool
+           { :I }
       }
-    \hbox_overlap_right:n { \box_use:N #1 }
-    \@@_scope_end:
-    \skip_horizontal:n { \box_wd:N #1 }
+      {#1} {#2}
+  }
+\cs_new_protected:Npn \@@_image_include_auxii:nnn #1#2#3
+  {
+    \int_if_exist:cTF { c__image_ #2#1 _int }
+      {
+        \tex_special:D
+          { pdf:usexobj~@image \int_use:c { c__image_ #2#1 _int } }
+      }
+      { \@@_image_include_auxiii:nn {#2} {#1} {#3} }
   }
+\cs_generate_variant:Nn \@@_image_include_auxii:nnn { x }
 %    \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.
+%  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 \@@_box_use_rotate:Nn #1#2
+\cs_new_protected:Npn \@@_image_include_auxiii:nnn #1#2#3
   {
-    \@@_scope_begin:
-    \@@_literal:n
+    \int_gincr:N \g_@@_image_int
+    \int_const:cn { c__image_ #1#2 _int } { \g_@@_image_int }
+    \tex_special:D
       {
-        \fp_compare:nNnTF {#2} = \c_zero_fp
-          { 0 }
-          { \fp_eval:n { round ( -#2 , 5 ) } } ~
-        rotate
+        pdf:#3~
+        @image \int_use:c { c__image_ #1#2 _int }
+        \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>> }
       }
-   \box_use:N #1
-   \@@_scope_end:
   }
+%    \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
 % \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:
-  }
+%</dvipdfmx|xdvipdfmx>
+%    \end{macrocode}
+%
+% \subsection{\texttt{xdvipdfmx} driver}
+%
+%    \begin{macrocode}
+%<*xdvipdfmx>
 %    \end{macrocode}
-% \end{macro}
 %
 % \subsubsection{Color}
 %
-% \begin{variable}{\l_@@_color_current_tl}
-%   The current color in driver-dependent format.
+% \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}
-\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 at 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 at color [ ] \q_stop
+      }
       { }
   }
 %</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{macro}[int]
+%   {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n}
+% \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 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_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
+\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
+  {
+    \int_zero:N \l__image_page_int
+    \@@_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 }
+\cs_new_protected:Npn \@@_image_getbb_auxi:nN #1#2
+  {
+    \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_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
+  {
+    \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_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_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_eps:n}
-%  The special syntax is relatively clear here: remember we need PostScript
-%  sizes here.
+% \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_eps:n #1
+\cs_new_protected:Npn \@@_image_include_pdf:n #1
   {
-    \tex_special:D { PSfile = #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>
+%    \end{macrocode}
+%
+% \subsection{Drawing commands: \texttt{pdfmode} and \texttt{(x)dvipdfmx}}
+%
+% Both \texttt{pdfmode} and \texttt{(x)dvipdfmx} directly produce PDF output
+% and understand a shared set of specials for drawing commands.
+%
+%    \begin{macrocode}
+%<*dvipdfmx|pdfmode|xdvipdfmx>
+%    \end{macrocode}
+%
 % \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).
+%   Pass data through using a dedicated interface.
 %     \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_literal:n #1
-  { \tex_special:D { ps:: ~ #1 } }
+\cs_new_eq:NN \@@_draw_literal:n \@@_literal:n
 \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.
+%   No special requirements here, so simply set up a drawing scope.
 %     \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 }
-  }
+  { \@@_draw_scope_begin: }
 \cs_new_protected:Npn \@@_draw_end:
-  {
-    \tex_special:D { ps::~@endspecial }
-    \tex_special:D { ps::~restore }
-    \tex_special:D { ps::[end] }
-  }
+  { \@@_draw_scope_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.
+%   In contrast to a general scope, a drawing scope is always done using
+%   the PDF operators so is the same for all relevant drivers.
 %     \begin{macrocode}
 \cs_new_protected:Npn \@@_draw_scope_begin:
-  { \@@_draw_literal:n { save } }
+  { \@@_draw_literal:n { q } }
 \cs_new_protected:Npn \@@_draw_scope_end:
-  { \@@_draw_literal:n { restore } }
+  { \@@_draw_literal:n { Q } }
 %    \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{macro}[int]{\@@_draw_rectangle:nnnn}
+%   Path creation operations all resolve directly to PDF 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.
 %     \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 }
+      { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ m }
   }
 \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
-      }
+      { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ l }
   }
 \cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6
   {
@@ -1813,16 +1883,25 @@
         \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
+        c
       }
  }
+\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4
+  {
+     \@@_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} ~
+        re
+      }
+  }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 % \end{macro}
 %
 % \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:}
-% \begin{variable}[aux]{\g_@@_draw_eor_bool}
+% \begin{variable}[int]{\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:
@@ -1843,102 +1922,34 @@
 %     \@@_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).
+%   }
+%   Converting paths to output is again a case of mapping directly to
+%   PDF operations.
 %     \begin{macrocode}
 \cs_new_protected:Npn \@@_draw_closepath:
-  { \@@_draw_literal:n { closepath } }
+  { \@@_draw_literal:n { h } }
 \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
-  }
+  { \@@_draw_literal:n { S } }
 \cs_new_protected:Npn \@@_draw_closestroke:
-  {
-    \@@_draw_closepath:
-    \@@_draw_stroke:
-  }
+  { \@@_draw_literal:n { s } }
 \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
+      { f \bool_if:NT \g_@@_draw_eor_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
+      { B \bool_if:NT \g_@@_draw_eor_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
+    \@@_draw_literal:x
+      { W \bool_if:NT \g_@@_draw_eor_bool * }
   }
+\cs_new_protected:Npn \@@_draw_discardpath:
+  { \@@_draw_literal:n { n } }
 %    \end{macrocode}
-% \end{variable}
 % \end{macro}
 %
 % \begin{macro}[int]{\@@_draw_dash:nn}
@@ -1951,7 +1962,7 @@
 %     \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel:
 %   }
 %   Converting paths to output is again a case of mapping directly to
-%   PostScript operations.
+%   PDF operations.
 %     \begin{macrocode}
 \cs_new_protected:Npn \@@_draw_dash:nn #1#2
   {
@@ -1960,7 +1971,7 @@
         [ ~
           \clist_map_function:nN {#1} \@@_draw_dash:n
         ] ~
-        \dim_to_decimal_in_bp:n {#2} ~ setdash
+        \dim_to_decimal_in_bp:n {#2} ~ d
       }
   }
 \cs_new:Npn \@@_draw_dash:n #1
@@ -1968,22 +1979,22 @@
 \cs_new_protected:Npn \@@_draw_linewidth:n #1
   {
     \@@_draw_literal:x
-      { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth }
+      { \dim_to_decimal_in_bp:n {#1} ~ w }
   }
 \cs_new_protected:Npn \@@_draw_miterlimit:n #1
-  { \@@_draw_literal:x { \fp_eval:n {#1} ~ setmiterlimit } }
+  { \@@_draw_literal:x { \fp_eval:n {#1} ~ M } }
 \cs_new_protected:Npn \@@_draw_cap_butt:
-  { \@@_draw_literal:n { 0 ~ setlinecap } }
+  { \@@_draw_literal:n { 0 ~ J } }
 \cs_new_protected:Npn \@@_draw_cap_round:
-  { \@@_draw_literal:n { 1 ~ setlinecap } }
+  { \@@_draw_literal:n { 1 ~ J } }
 \cs_new_protected:Npn \@@_draw_cap_rectangle:
-  { \@@_draw_literal:n { 2 ~ setlinecap } }
+  { \@@_draw_literal:n { 2 ~ J } }
 \cs_new_protected:Npn \@@_draw_join_miter:
-  { \@@_draw_literal:n { 0 ~ setlinejoin } }
+  { \@@_draw_literal:n { 0 ~ j } }
 \cs_new_protected:Npn \@@_draw_join_round:
-  { \@@_draw_literal:n { 1 ~ setlinejoin } }
+  { \@@_draw_literal:n { 1 ~ j } }
 \cs_new_protected:Npn \@@_draw_join_bevel:
-  { \@@_draw_literal:n { 2 ~ setlinejoin } }
+  { \@@_draw_literal:n { 2 ~ j } }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
@@ -1991,118 +2002,109 @@
 % \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}[aux]{\@@_draw_color_cmyk_aux:nnnn}
 % \begin{macro}[int]
 %   {
 %     \@@_draw_color_gray:n        ,
 %     \@@_draw_color_gray_fill:n   ,
 %     \@@_draw_color_gray_stroke:n
 %   }
+% \begin{macro}[aux]{\@@_draw_color_gray_aux: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{macro}[aux]{\@@_draw_color_rgb_aux:nnn}
+%   Yet more fast conversion, all using the FPU to allow for expressions
+%   in numerical input.
 %     \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
+    \use:x
       {
-        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
-        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
-        setcmykcolor ~
+        \@@_draw_color_cmyk_aux:nnnn
+          { \fp_eval:n {#1} }
+          { \fp_eval:n {#2} }
+          { \fp_eval:n {#3} }
+          { \fp_eval:n {#4} }
       }
-    \@@_draw_color_reset:
+  }
+\cs_new_protected:Npn \@@_draw_color_cmyk_aux:nnnn #1#2#3#4
+  {
+    \@@_draw_literal:n
+      { #1 ~ #2 ~ #3 ~ #4 ~ k ~ #1 ~ #2 ~ #3 ~ #4 ~ K }
   }
 \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
+        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+        k
       }
   }
 \cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
   {
-    \__driver_draw_literal:x
+    \@@_draw_literal:x
       {
-        /l3sc ~
-          {
-            \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
-            \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
-            setcmykcolor
-          } ~
-        def
+        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+        K
       }
   }
 \cs_new_protected:Npn \@@_draw_color_gray:n #1
   {
-    \@@_draw_literal:x { fp_eval:n {#1} ~ setgray  }
-    \@@_draw_color_reset:
+    \use:x
+      { \@@_draw_color_gray_aux:n { \fp_eval:n {#1} } }
+  }
+\cs_new_protected:Npn \@@_draw_color_gray_aux:n #1
+  {
+    \@@_draw_literal:n { #1 ~ g ~ #1 ~ G }
   }
 \cs_new_protected:Npn \@@_draw_color_gray_fill:n #1
-  { \@@_draw_literal:x { /l3fc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
+  { \@@_draw_literal:x { \fp_eval:n {#1} ~ g } }
 \cs_new_protected:Npn \@@_draw_color_gray_stroke:n #1
-  { \@@_draw_literal:x { /l3sc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
+  { \@@_draw_literal:x { \fp_eval:n {#1} ~ G } }
 \cs_new_protected:Npn \@@_draw_color_rgb:nnn #1#2#3
   {
-    \@@_draw_literal:x
+    \use:x
       {
-        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
-        setrgbcolor
+        \@@_draw_color_rgb_aux:nnn
+          { \fp_eval:n {#1} }
+          { \fp_eval:n {#2} }
+          { \fp_eval:n {#3} }
       }
-    \@@_draw_color_reset:
+  }
+\cs_new_protected:Npn \@@_draw_color_rgb_aux:nnn #1#2#3
+  {
+    \@@_draw_literal:n
+      { #1 ~ #2 ~ #3 ~ rg ~ #1 ~ #2 ~ #3 ~ RG }
   }
 \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
-      }
+      { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ rg }
   }
 \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
-      }
+      { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ RG }
   }
 %    \end{macrocode}
 % \end{macro}
 % \end{macro}
 % \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
@@ -2113,49 +2115,47 @@
   {
     \@@_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
+        \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} ~
+        cm
       }
   }
 %    \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{variable}[aux]{\l_@@_tmp_box}
+%   Inserting a \TeX{} box transformed to the requested position and using
+%   the current matrix is done using a mixture of \TeX{} and low-level
+%   manipulation. The offset can be handled by \TeX{}, so only any rotation/^^A
+%   skew/scaling component needs to be done using the matrix operation. As this
+%   operation can never be cached, the scope is set directly not using the
+%   \texttt{draw} version.
 %     \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:
+    \hbox_set:Nn \l_@@_tmp_box
+      {
+        \tex_kern:D \__dim_eval:w #6 \__dim_eval_end:
+        \@@_scope_begin:
+        \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5}
+          { 0pt } { 0pt }
+        \box_move_up:nn {#7} { \box_use:N #1 }
+        \@@_scope_end:
+      }
+    \box_set_wd:Nn \l_@@_tmp_box { 0pt }
+    \box_set_ht:Nn \l_@@_tmp_box { 0pt }
+    \box_set_dp:Nn \l_@@_tmp_box { 0pt }
+    \box_use:N \l_@@_tmp_box
   }
+\box_new:N \l_@@_tmp_box
 %    \end{macrocode}
+% \end{variable}
 % \end{macro}
 %
 %    \begin{macrocode}
-%</dvips>
+%</dvipdfmx|pdfmode|xdvipdfmx>
 %    \end{macrocode}
 %
 % \subsection{\texttt{dvisvgm} driver}

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the latex3-commits mailing list