% \iffalse meta-comment
%
%% File: l3drivers.dtx Copyright(C) 2011-2016 The LaTeX3 Project
%%
%% It may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License (LPPL), either version 1.3c of this
%% license or (at your option) any later version.  The latest version
%% of this license is in the file
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the "l3kernel bundle" (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%%
%
%<*driver>
\documentclass[full]{l3doc}
%</driver>
%<*driver|package>
\GetIdInfo$Id: l3drivers.dtx 6644 2016-08-13 20:22:11Z bruno $
  {L3 Experimental drivers}
%</driver|package>
%<*driver>
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \textsf{l3drivers} package\\ Drivers^^A
%   \thanks{This file describes v\ExplFileVersion,
%     last revised \ExplFileDate.}^^A
% }
%
% \author{^^A
%  The \LaTeX3 Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released \ExplFileDate}
%
% \maketitle
%
% \begin{documentation}
%
% \TeX{} relies on drivers in order to carry out a number of tasks, such
% as using color, including graphics and setting up hyper-links. The nature
% of the code required depends on the exact driver in use. Currently,
% \LaTeX3 is aware of the following drivers:
% \begin{itemize}
%   \item \texttt{pdfmode}:  The \enquote{driver} for direct PDF output by
%     \emph{both} \pdfTeX{} and \LuaTeX{} (no separate driver is used in this
%     case: the engine deals with PDF creation itself).
%   \item \texttt{dvips}: The \texttt{dvips} program, which works in
%     conjugation with \pdfTeX{} or \LuaTeX{} in DVI mode.
%   \item \texttt{dvipdfmx}: The \texttt{dvipdfmx} program, which works in
%     conjugation with \pdfTeX{} or \LuaTeX{} in DVI mode.
%   \item \texttt{dvisvgm}:  The \texttt{dvisvgm} program, which works in
%     conjugation with \pdfTeX{} or \LuaTeX{} in DVI mode to create SVG
%     output.
%   \item \texttt{xdvipdfmx}: The driver used by \XeTeX{}.
% \end{itemize}
%
% The code here is all very low-level, and should not in general be used
% outside of the kernel. It is also important to note that many of the
% functions here are closely tied to the immediate level \enquote{up},
% and they must be used in the correct contexts.d
%
% \section{Box clipping}
%
% \begin{function}[added = 2011-11-11]{\__driver_box_use_clip:N}
%   \begin{syntax}
%     \cs{__driver_box_use_clip:N} \meta{box}
%   \end{syntax}
%   Inserts the content of the \meta{box} at the current insertion point
%   such that any material outside of the bounding box will not be displayed
%   by the driver. The material in the \meta{box} is still placed in the
%   output stream: the clipping takes place at a driver level.
%
%   This function should only be used within a surrounding horizontal
%   box construct.
% \end{function}
%
% \section{Box rotation and scaling}
%
% \begin{function}[added = 2016-05-12]{\__driver_box_use_rotate:Nn}
%   \begin{syntax}
%     \cs{__driver_box_use_rotate:Nn} \meta{box} \Arg{angle}
%   \end{syntax}
%   Inserts the content of the \meta{box} at the current insertion point
%   rotated by the \meta{angle} (expressed in degrees). The material is
%   inserted with no apparent height or width, and is rotated such the
%   the \TeX{} reference point of the box is the center of rotation and
%   remains the reference point after rotation. It is the responsibly of
%   the code using this function to adjust the apparent size of the box to
%   be correct at the \TeX{} side.
%
%   This function should only be used within a surrounding horizontal
%   box construct.
% \end{function}
%
% \begin{function}[added = 2016-05-12]{\__driver_box_use_scale:Nnn}
%   \begin{syntax}
%     \cs{__driver_box_use_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale}
%   \end{syntax}
%   Inserts the content of the \meta{box} at the current insertion point
%   scale by the \meta{x-scale} and \meta{y-scale}. The material is
%   inserted with no apparent height or width. It is the responsibly of
%   the code using this function to adjust the apparent size of the box to
%   be correct at the \TeX{} side.
%
%   This function should only be used within a surrounding horizontal
%   box construct.
% \end{function}
%
% \section{Color support}
%
% \begin{function}[added = 2011-09-03, updated = 2012-05-18]
%   {\__driver_color_ensure_current:}
%   \begin{syntax}
%     \cs{__driver_color_ensure_current:}
%   \end{syntax}
%   Ensures that the color used to typeset material is that which was
%   set when the material was placed in a box. This function is therefore
%   required inside any \enquote{color safe} box to ensure that the box may
%   be inserted in a location where the foreground color has been altered,
%   while preserving the color used in the box.
% \end{function}
%
% \section{Drawing}
%
% The drawing functions provided here are \emph{highly} experimental. They
% are inspired heavily by the system layer of \pkg{pgf} (most have the
% same interface as the same functions in the latter's \cs{pgfsys@\ldots}
% namespace). They are intended to form the basis for higher level drawing
% interfaces, which themselves are likely to be further abstracted for user
% access. Again, this model is heavily inspired by \pkg{pgf} and
% Ti\textit{k}z.
%
% These low level drawing interfaces abstract from the driver raw requirements
% but still require an appreciation of the concepts of PostScript/PDF/SVG
% graphic creation.
%
% \begin{function}
%   { \__driver_draw_begin:,  \__driver_draw_end:}
%   \begin{syntax}
%     \cs{__driver_draw_begin:}
%     \meta{content}
%     \cs{__driver_draw_end:}
%   \end{syntax}
%   Defines a drawing environment. This will be a scope for the purposes of
%   the graphics state. Depending on the driver, other set up may or may not
%   take place here. The natural size of the \meta{content} should be zero
%   from the \TeX{} perspective: allowance for the size of the content must
%   be made at a higher level (or indeed this can be skipped if the content is
%   to overlap other material).
% \end{function}
%
% \begin{function}
%   {\__driver_draw_scope_begin:,  \__driver_draw_scope_end:}
%   \begin{syntax}
%     \cs{__driver_draw_scope_begin:}
%     \meta{content}
%     \cs{__driver_draw_scope_end:}
%   \end{syntax}
%   Defines a scope for drawing settings and so on. Changes to the graphic
%   state and concepts such as color or linewidth are localised to a scope.
%   This function pair must never be used if an partial path is under
%   construction: such paths must be entirely contained at one unbroken
%   scope level. Note that scopes do not form \TeX{} groups and may not
%   be aligned with them.
% \end{function}
%
% \subsection{Path construction}
%
% \begin{function}{\__driver_draw_moveto:nn}
%   \begin{syntax}
%     \cs{__driver_draw_move:nn} \Arg{x} \Arg{y}
%   \end{syntax}
%   Moves the current drawing reference point to (\meta{x}, \meta{y});
%   any active transformation matrix will apply.
% \end{function}
%
% \begin{function}{\__driver_draw_lineto:nn}
%   \begin{syntax}
%     \cs{__driver_draw_lineto:nn} \Arg{x} \Arg{y}
%   \end{syntax}
%   Adds a path from the current drawing reference point to
%   (\meta{x}, \meta{y}); any active transformation matrix will apply. Note
%   that nothing is drawn until a fill or stroke operation is applied, and that
%   the path may be discarded or used as a clip without appearing itself.
% \end{function}
%
% \begin{function}{\__driver_draw_curveto:nnnnnn}
%   \begin{syntax}
%     \cs{__driver_draw_curveto:nnnnnn} \Arg{x_1} \Arg{y_1}
%       \Arg{x_2} \Arg{y_2} \Arg{x_3} \Arg{y_3}
%   \end{syntax}
%   Adds a Bezier curve path from the current drawing reference point to
%   (\meta{x_3}, \meta{y_3}), using (\meta{x_1}, \meta{y_1}) and
%   (\meta{x_2}, \meta{y_2}) as control points; any active transformation
%   matrix will apply.  Note that nothing is drawn until a fill or stroke
%   operation is applied, and that the path may be discarded or used as a clip
%   without appearing itself.
% \end{function}
%
% \begin{function}{\__driver_draw_rectangle:nnnn}
%   \begin{syntax}
%     \cs{__driver_draw_rectangle:nnnn} \Arg{x} \Arg{y} \Arg{width} \Arg{height}
%   \end{syntax}
%   Adds rectangular path from (\meta{x_1}, \meta{y_1}) of \meta{height}
%   and \meta{width}; any active transformation matrix will apply.  Note that
%   nothing is drawn until a fill or stroke operation is applied, and that the
%   path may be discarded or used as a clip without appearing itself.
% \end{function}
%
% \begin{function}{\__driver_draw_closepath:}
%   \begin{syntax}
%     \cs{__driver_draw_closepath:}
%   \end{syntax}
%   Closes an existing path, adding a line from the current point to the
%   start of path. Note that nothing is drawn until a fill or stroke
%   operation is applied, and that the path may be discarded or used as a clip
%   without appearing itself.
% \end{function}
%
% \subsection{Stroking and filling}
%
% \begin{function}{\__driver_draw_stroke:, \__driver_draw_closestroke:}
%   \begin{syntax}
%     \meta{path construction}
%     \cs{__driver_draw_stroke:}
%   \end{syntax}
%   Draws a line alone the current path, which will also be closed when
%   \cs{__driver_draw_closestroke:} is used. The nature of the line drawn
%   is influenced by settings for
%   \begin{itemize}
%     \item Line thickness
%     \item Stroke color (or the current color if no specific stroke color
%       is set)
%     \item Line capping (how non-closed line ends should look)
%     \item Join style (how a bend in the path should be rendered)
%     \item Dash pattern
%   \end{itemize}
%   The path may also be used for clipping.
% \end{function}
%
% \begin{function}{\__driver_draw_fill:, \__driver_draw_fillstroke:}
%   \begin{syntax}
%     \meta{path construction}
%     \cs{__driver_draw_fill:}
%   \end{syntax}
%   Fills the area surrounded by the current path: this will be closed prior
%   to filling if it is not already. The \texttt{fillstroke} version will also
%   stroke the path as described for \cs{__driver_draw_stroke:}. The fill is
%   influenced by the setting for fill color (or the current color if no
%   specific stroke color is set). The path may also be used for clipping.
%   For paths which are self-intersecting or comprising multiple parts, the
%   determination of which areas are inside the path is made using the non-zero
%   winding number rule unless the even-odd rule is active.
% \end{function}
%
% \begin{function}{\__driver_draw_nonzero_rule:, \__driver_draw_evenodd_rule:}
%   \begin{syntax}
%     \cs{__driver_draw_nonzero_rule:}
%   \end{syntax}
%   Active either the non-zero winding number or the even-odd rule,
%   respectively, for determining what is inside a fill or clip area.
%   For technical reasons, these command are not influenced by scoping
%   and apply on an ongoing basis.
% \end{function}
%
% \begin{function}{\__driver_draw_clip:}
%   \begin{syntax}
%     \meta{path construction}
%     \cs{__driver_draw_clip:}
%   \end{syntax}
%   Indicates that the current path should be used for clipping, such that
%   any subsequent material outside of the path (but within the current
%   scope) will not be shown. This command should be given once a path is
%   complete but before it is stroked or filled (if appropriate). This
%   command is \emph{not} affected by scoping: it applies to exactly one
%   path as shown.
% \end{function}
%
% \begin{function}{\__driver_draw_discardpath:}
%   \begin{syntax}
%     \meta{path construction}
%     \cs{__driver_draw_discardpath:}
%   \end{syntax}
%   Discards the current path without stroking or filling. This is primarily
%   useful for paths constructed purely for clipping, as this alone does not
%   end the paths existence.
% \end{function}
%
% \subsection{Stroke options}
%
% \begin{function}{\__driver_draw_linewidth:n}
%   \begin{syntax}
%     \cs{__driver_draw_linewidth:n} \Arg{dimexpr}
%   \end{syntax}
%   Sets the width to be used for stroking to \meta{dimexpr}.
% \end{function}
%
% \begin{function}{\__driver_draw_dash:nn}
%   \begin{syntax}
%     \cs{__driver_draw_dash:nn} \Arg{dash pattern} \Arg{phase}
%   \end{syntax}
%   Sets the pattern of dashing to be used when stroking a line. The
%   \meta{dash pattern} should be a comma-separated list of dimension
%   expressions. This is then interpreted as a series of pairs of line-on
%   and line-off lengths. For example \texttt{3pt, 4pt} means that $3$\,pt on,
%   $4$\,pt off, $3$\,pt on, and so on. A more complex pattern will also
%   repeat: \texttt{3pt, 4pt, 1pt, 2pt} results in $3$\,pt on, $4$\,pt off,
%   $1$\,pt on, $2$\,pt off, $3$\,pt on, and so on. An odd number of entries
%   means that the last is repeated, for example \texttt{3pt} is equal to
%   \texttt{3pt, 3pt}. An empty pattern yields a solid line.
%
%   The \meta{phase} specifies an offset at the start of the cycle. For
%   example, with a pattern \texttt{3pt} a phase of \texttt{1pt} will mean
%   that the output is $2$\,pt on, $3$\,pt off, $3$\,pt on, $3$\,pt on,
%   \emph{etc.}
% \end{function}
%
% \begin{function}
%   {
%     \__driver_draw_cap_butt:      ,
%     \__driver_draw_cap_rectangle: ,
%     \__driver_draw_cap_round:
%   }
%   \begin{syntax}
%     \cs{__driver_draw_cap_butt:}
%   \end{syntax}
%   Sets the style of terminal stroke position to one of butt, rectangle or
%   round.
% \end{function}
%
% \begin{function}
%   {
%     \__driver_draw_join_bevel:      ,
%     \__driver_draw_join_miter: ,
%     \__driver_draw_join_round:
%   }
%   \begin{syntax}
%     \cs{__driver_draw_cap_butt:}
%   \end{syntax}
%   Sets the style of stroke joins to one of bevel, miter or round.
% \end{function}
%
% \begin{function}{\__driver_draw_miterlimit:n}
%   \begin{syntax}
%     \cs{__driver_draw_miterlimit:n} \Arg{dimexpr}
%   \end{syntax}
%   Sets the miter limit of lines joined as a miter, as described in the
%   PDF and PostScript manuals.
% \end{function}
%
% \subsection{Color}
%
% \begin{function}
%   {
%     \__driver_draw_color_cmyk:nnnn ,
%     \__driver_draw_color_cmyk_fill:nnnn ,
%     \__driver_draw_color_cmyk_stroke:nnnn
%   }
%   \begin{syntax}
%     \cs{__driver_draw_color_cmyk:nnnn} \Arg{cyan} \Arg{magneta} \Arg{yellow}
%       \Arg{black}
%   \end{syntax}
%   Sets the color for drawing to the CMYK values specified, all of which are
%   fp expressions which should evaluate to between $0$ and $1$. The
%   \texttt{fill} and \texttt{stroke} versions set only the color for those
%   operations. Note that the general setting is more efficient with some
%   drivers so should in most cases be preferred.
% \end{function}
%
% \begin{function}
%   {
%     \__driver_draw_color_gray:n ,
%     \__driver_draw_color_gray_fill:n ,
%     \__driver_draw_color_gray_stroke:n
%   }
%   \begin{syntax}
%     \cs{__driver_draw_color_gray:n} \Arg{gray}
%   \end{syntax}
%   Sets the color for drawing to the grayscale value specified, which is
%   fp expressions which should evaluate to between $0$ and $1$. The
%   \texttt{fill} and \texttt{stroke} versions set only the color for those
%   operations. Note that the general setting is more efficient with some
%   drivers so should in most cases be preferred.
% \end{function}
%
% \begin{function}
%   {
%     \__driver_draw_color_rgb:nnn ,
%     \__driver_draw_color_rgb_fill:nnn ,
%     \__driver_draw_color_rgb_stroke:nnn
%   }
%   \begin{syntax}
%     \cs{__driver_draw_color_gray:n} \Arg{red} \Arg{green} \Arg{blue}
%   \end{syntax}
%   Sets the color for drawing to the RGB values specified, all of which are
%   fp expressions which should evaluate to between $0$ and $1$. The
%   \texttt{fill} and \texttt{stroke} versions set only the color for those
%   operations. Note that the general setting is more efficient with some
%   drivers so should in most cases be preferred.
% \end{function}
%
% \subsection{Inserting \TeX{} material}
%
% \begin{function}{\__driver_draw_hbox:nnnnnn}
%   \begin{syntax}
%     \cs{__driver_draw_hbox:Nnnnnnn} \meta{box}
%       \Arg{a} \Arg{b} \Arg{c} \Arg{d} \Arg{x} \Arg{y}
%   \end{syntax}
%   Inserts the \meta{box} as an hbox with the box reference point placed
%   at ($x$, $y$). The transformation matrix $[a b c d]$ will be applied
%   to the box, allowing it to be in synchronisation with any scaling, rotation
%   or skewing applying more generally. Note that \TeX{} material should not
%   be inserted directly into a drawing as it will not be in the correct
%   location. Also note that as for other drawing elements the box here will
%   have no size from a \TeX{} perspective.
% \end{function}
%
% \subsection{Coordinate system transformations}
%
% \begin{function}{\__driver_draw_transformcm:nnnnnn}
%   \begin{syntax}
%     \cs{__driver_draw_transformcm:nnnnnn} \Arg{a} \Arg{b} \Arg{c} \Arg{d}
%       \Arg{x} \Arg{y}
%   \end{syntax}
%   Applies the transformation matrix $[a b c d]$ and offset vector
%   ($x$, $y$) to the current graphic state. This will affect any subsequent
%   items in the same scope but not those already given.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3drivers} Implementation}
%
%    \begin{macrocode}
%<*initex|package>
%<@@=driver>
%    \end{macrocode}
%
% Whilst there is a reasonable amount of code overlap between drivers,
% it is much clearer to have the blocks more-or-less separated than run
% in together and DocStripped out in parts. As such, most of the following
% is set up on a per-driver basis, though there is some common code (again
% given in blocks not interspersed with other material).
%
% All the file identifiers are up-front so that they come out in the right
% place in the files.
%    \begin{macrocode}
%<*package>
\ProvidesExplFile
%<*dvipdfmx>
  {l3dvidpfmx.def}{\ExplFileDate}{\ExplFileVersion}
  {L3 Experimental driver: dvipdfmx}
%</dvipdfmx>
%<*dvips>
  {l3dvips.def}{\ExplFileDate}{\ExplFileVersion}
  {L3 Experimental driver: dvips}
%</dvips>
%<*dvisvgm>
  {l3dvisvgm.def}{\ExplFileDate}{\ExplFileVersion}
  {L3 Experimental driver: dvisvgm}
%</dvisvgm>
%<*pdfmode>
  {l3pdfmode.def}{\ExplFileDate}{\ExplFileVersion}
  {L3 Experimental driver: PDF mode}
%</pdfmode>
%<*xdvipdfmx>
  {l3xdvidpfmx.def}{\ExplFileDate}{\ExplFileVersion}
  {L3 Experimental driver: xdvipdfmx}
%</xdvipdfmx>
%</package>
%    \end{macrocode}
%
% \subsection{\texttt{pdfmode} driver}
%
%    \begin{macrocode}
%<*pdfmode>
%    \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).
%    \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]{\@@_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]{\@@_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}
%
% \subsubsection{Color}
%
% \begin{variable}{\l_@@_current_color_tl}
%   The current color in driver-dependent format: pick up the package-mode
%   data if available.
%    \begin{macrocode}
\tl_new:N \l_@@_current_color_tl
\tl_set:Nn \l_@@_current_color_tl { 0~g~0~G }
%<*package>
\AtBeginDocument
  {
    \@ifpackageloaded { color }
      { \tl_set:Nn \l_@@_current_color_tl { \current@color } }
      { }
  }
%</package>
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_color_stack_int}
%   \pdfTeX{} and \LuaTeX{} have multiple stacks available, and to track
%   which one is in use a variable is required.
%    \begin{macrocode}
\int_new:N \l_@@_color_stack_int
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\@@_color_ensure_current:}
% \begin{macro}[aux]{\@@_color_reset:}
%   There is a dedicated primitive/primitive interface for setting colors.
%   As with scoping, this approach is not suitable for cached operations.
%    \begin{macrocode}
\cs_new_protected:Npx \@@_color_ensure_current:
  {
    \cs_if_exist:NTF \luatex_pdfextension:D
      { \luatex_pdfextension:D colorstack }
      { \pdftex_pdfcolorstack:D }
        \exp_not:N \l_@@_color_stack_int push
          { \exp_not:N \l_@@_current_color_tl }
    \group_insert_after:N \exp_not:N \@@_color_reset:
  }
\cs_new_protected:Npx \@@_color_reset:
  {
    \cs_if_exist:NTF \luatex_pdfextension:D
      { \luatex_pdfextension:D colorstack }
      { \pdftex_pdfcolorstack:D }
        \exp_not:N \l_@@_color_stack_int pop \scan_stop:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \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 favoured as the link to
%   the \pdfTeX{} primitive approach is clearer.
%    \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 direct PDF operations here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_scope_begin:
  { \@@_literal:n { q } }
\cs_new_protected:Npn \@@_scope_end:
  { \@@_literal:n { Q } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_matrix:n}
%   With \texttt{(x)dvipdfmx} the matrix has to include a translation
%   part: that is always zero and so is built in here so that the same
%   internal interface works for all PDF-related drivers.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_matrix:n #1
  { \@@_literal:n { #1 \c_space_tl 0~0~cm } }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Color}
%
% \begin{variable}{\l_@@_current_color_tl}
%   The current color in driver-dependent format.
%    \begin{macrocode}
\tl_new:N \l_@@_current_color_tl
\tl_set:Nn \l_@@_current_color_tl { [ 0 ] }
%<*package>
\AtBeginDocument
  {
    \@ifpackageloaded { color }
      { \tl_set:Nn \l_@@_current_color_tl { \current@color } }
      { }
  }
%</package>
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\@@_color_ensure_current:}
% \begin{macro}[aux]{\@@_color_reset:}
%   Directly set the color using the specials with optimisation support.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_color_ensure_current:
  {
    \tex_special:D { pdf:bcolor~\l_@@_current_color_tl }
    \group_insert_after:N \@@_color_reset:
  }
\cs_new_protected:Npn \@@_color_reset:
  { \tex_special:D { pdf:ecolor } }
%    \end{macrocode}
% \end{macro}
% \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:}
%   The \LaTeXe{} driver uses \texttt{dvips}-like specials so there has to
%   be a change of set up if \pkg{color} is loaded.
%    \begin{macrocode}
%<*package>
\AtBeginDocument
  {
    \@ifpackageloaded { color }
      {
        \cs_set_protected:Npn \@@_color_ensure_current:
          {
            \tex_special:D { color~push~\l_@@_current_color_tl }
            \group_insert_after:N \@@_color_reset:
          }
        \cs_set_protected:Npn \@@_color_reset:
          { \tex_special:D { color~pop } }
      }
      { }
  }
%</package>
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%</xdvipdfmx>
%    \end{macrocode}
%
% \subsection{Common code for PDF production}
%
% As all of the drivers which understand PDF-targeted specials act in much
% the same way there is a lot of shared code. Rather than try to DocStrip it
% interspersed with the above, we collect all of it here.
%
%    \begin{macrocode}
%<*dvipdfmx|pdfmode|xdvipdfmx>
%    \end{macrocode}
%
% \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
  {
    \@@_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 }
  }
%    \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{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}{\@@_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
  {
    \@@_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:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Drawing}
%
% \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 }
%    \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: }
%    \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 } }
%    \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
  {
     \@@_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}
%    The even-odd rule here can be implemented as a simply switch.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_evenodd_rule:
  { \bool_gset_true:N \g_@@_draw_eor_bool }
\cs_new_protected:Npn \@@_draw_nonzero_rule:
  { \bool_gset_false:N \g_@@_draw_eor_bool }
\bool_new:N \g_@@_draw_eor_bool
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
% \begin{macro}[int]
%   {
%     \@@_draw_closepath:   ,
%     \@@_draw_stroke:      ,
%     \@@_draw_closestroke: ,
%     \@@_draw_fill:        ,
%     \@@_draw_fillstroke:  ,
%     \@@_draw_clip:        ,
%     \@@_draw_discardpath:
%   }
%   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:
  {
    \@@_draw_literal:x
      { B \bool_if:NT \g_@@_draw_eor_bool * }
  }
\cs_new_protected:Npn \@@_draw_clip:
  {
    \@@_draw_literal:x
      { W \bool_if:NT \g_@@_draw_eor_bool * }
  }
\cs_new_protected:Npn \@@_draw_discardpath:
  { \@@_draw_literal:n { n } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_dash:nn}
% \begin{macro}[aux]{\@@_draw_dash:n}
% \begin{macro}[int]{\@@_draw_linewidth:n}
% \begin{macro}[int]{\@@_draw_miterlimit:n}
% \begin{macro}[int]
%   {
%     \@@_draw_cap_butt:, \@@_draw_cap_round:, \@@_draw_cap_rectangle:,
%     \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel:
%   }
%   Converting paths to output is again a case of mapping directly to
%   PDF operations.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_dash:nn #1#2
  {
    \@@_draw_literal:x
      {
        [ ~
          \clist_map_function:nN {#1} \@@_draw_dash:n
        ] ~
        \dim_to_decimal_in_bp:n {#2} ~ d
      }
  }
\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} ~ w }
  }
\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}
%
% \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
  {
    \use:x
      {
        \@@_draw_color_cmyk_aux:nnnn
          { \fp_eval:n {#1} }
          { \fp_eval:n {#2} }
          { \fp_eval:n {#3} }
          { \fp_eval:n {#4} }
      }
  }
\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
      {
        \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
  {
    \@@_draw_literal:x
      {
        \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
  {
    \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 { \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
  {
    \use:x
      {
        \@@_draw_color_rgb_aux:nnn
          { \fp_eval:n {#1} }
          { \fp_eval:n {#2} }
          { \fp_eval:n {#3} }
      }
  }
\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 }
  }
%    \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} ~
        cm
      }
  }
%    \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
  {
    \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}
%</dvipdfmx|pdfmode|xdvipdfmx>
%    \end{macrocode}
%
% \subsection{\texttt{dvips} driver}
%
%    \begin{macrocode}
%<*dvips>
%    \end{macrocode}
%
% \subsubsection{Basics}
%
% \begin{macro}[int]{\@@_literal:n}
%   In the case of \texttt{dvips} there is no build-in saving of the current
%   position, and so some additional PostScript is required to set up the
%   transformation matrix and also to restore it afterwards. Notice the use
%   of the stack to save the current position \enquote{up front} and to
%   move back to it at the end of the process.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_literal:n #1
  {
    \tex_special:D
      {
        ps:
          currentpoint~
          currentpoint~translate~
          #1 ~
          neg~exch~neg~exch~translate
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_scope_begin:, \@@_scope_end:}
%   Scope saving/restoring is done directly with no need to worry about the
%   transformation matrix. General scoping is only for the graphics stack so
%   the lower-cost |gsave|/|grestore| pair are used.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_scope_begin:
  { \tex_special:D { ps:gsave } }
\cs_new_protected:Npn \@@_scope_end:
  { \tex_special:D { ps:grestore } }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Driver-specific auxiliaries}
%
% \begin{macro}[int, EXP]{\@@_absolute_lengths:n}
%   The \texttt{dvips} driver scales all absolute dimensions based
%   on the output resolution selected and any \TeX{} magnification. Thus
%   for any operation involving absolute lengths there is a correction to
%   make. This is based on \texttt{normalscale} from \texttt{special.pro}
%   but using the stack rather than a definition to save the current matrix.
%    \begin{macrocode}
\cs_new:Npn \@@_absolute_lengths:n #1
  {
     matrix~currentmatrix~
     Resolution~72~div~VResolution~72~div~scale~
     DVImag~dup~scale~
     #1 ~
     setmatrix
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Box operations}
%
% \begin{macro}{\@@_box_use_clip:N}
%   Much the same idea as for the PDF mode version but with a slightly
%   different syntax for creating the clip path. To avoid any scaling
%   issues we need the absolute length auxiliary here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_clip:N #1
  {
    \@@_scope_begin:
    \@@_literal:n
      {
        \@@_absolute_lengths:n
          {
            0 ~
            \dim_to_decimal_in_bp:n { \box_dp:N #1 } ~
            \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
            \dim_to_decimal_in_bp:n { -\box_ht:N #1 - \box_dp:N #1 } ~
            rectclip
          }
      }
    \hbox_overlap_right:n { \box_use:N #1 }
    \@@_scope_end:
    \skip_horizontal:n { \box_wd:N #1 }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_box_use_rotate:Nn}
%   Rotating using \texttt{dvips} does not require that the box dimensions
%   are altered and has a very convenient built-in operation. Zero rotation
%   must be written as |0| not |-0| so there is a quick test.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
  {
    \@@_scope_begin:
    \@@_literal:n
      {
        \fp_compare:nNnTF {#2} = \c_zero_fp
          { 0 }
          { \fp_eval:n { round ( -#2 , 5 ) } } ~
        rotate
      }
   \box_use:N #1
   \@@_scope_end:
  }
% \end{macro}
%
% \begin{macro}{\@@_box_use_scale:Nnn}
%   The \texttt{dvips} driver once again has a dedicated operation we can
%   use here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
  {
    \@@_scope_begin:
    \@@_literal:n
      {
        \fp_eval:n { round ( #2 , 5 ) } ~
        \fp_eval:n { round ( #3 , 5 ) } ~
        scale
      }
    \hbox_overlap_right:n { \box_use:N #1 }
    \@@_scope_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Color}
%
% \begin{variable}{\l_@@_current_color_tl}
%   The current color in driver-dependent format.
%    \begin{macrocode}
\tl_new:N \l_@@_current_color_tl
\tl_set:Nn \l_@@_current_color_tl { gray~0 }
%<*package>
\AtBeginDocument
  {
    \@ifpackageloaded { color }
      { \tl_set:Nn \l_@@_current_color_tl { \current@color } }
      { }
  }
%</package>
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\@@_color_ensure_current:}
% \begin{macro}[aux]{\@@_color_reset:}
%   Directly set the color using the specials: no optimisation here.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_color_ensure_current:
  {
    \tex_special:D { color~push~\l_@@_current_color_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{Drawing}
%
% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x}
%   Literals with no positioning (using |ps:| each one is positioned but
%   cut of from everything else, so no good for the stepwise approach needed
%   here).
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_literal:n #1
  { \tex_special:D { ps:: ~ #1 } }
\cs_generate_variant:Nn \@@_draw_literal:n { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_begin:, \@@_draw_end:}
%   The |ps::[begin]| special here deals with positioning but allows us to
%   continue on to a matching |ps::[end]|: contrast with |ps:|, which positions
%   but where we can't split material between separate calls. The
%   |@beginspecial|/|@endspecial| pair are from |special.pro| and correct the
%   scale and $y$-axis direction. The reference point at the start of the box
%   is saved (as |l3x|/|l3y|) as it is needed when inserting various items.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_begin:
  {
    \tex_special:D { ps::[begin] }
    \tex_special:D { ps::~save }
    \tex_special:D { ps::~/l3x~currentpoint~/l3y~exch~def~def }
    \tex_special:D { ps::~@beginspecial }
  }
\cs_new_protected:Npn \@@_draw_end:
  {
    \tex_special:D { ps::~@endspecial }
    \tex_special:D { ps::~restore }
    \tex_special:D { ps::[end] }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_scope_begin:, \@@_draw_scope_end:}
%   Scope here may need to contain saved definitions, so the entire memory
%   rather than just the graphic state has to be sent to the stack.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_scope_begin:
  { \@@_draw_literal:n { save } }
\cs_new_protected:Npn \@@_draw_scope_end:
  { \@@_draw_literal:n { restore } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_moveto:nn, \@@_draw_lineto:nn}
% \begin{macro}[int]{\@@_draw_rectangle:nnnn}
% \begin{macro}[int]{\@@_draw_curveto:nnnnnn}
%   Path creation operations mainly resolve directly to PostScript primitive
%   steps, with only the need to convert to \texttt{bp}. Notice that
%   \texttt{x}-type expansion is included here to ensure that any variable
%   values are forced to literals before any possible caching. There is
%   no native rectangular path command (without also clipping, filling or
%   stroking), so that task is done using a small amount of PostScript.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_moveto:nn #1#2
  {
    \@@_draw_literal:x
      { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ moveto }
  }
\cs_new_protected:Npn \@@_draw_lineto:nn #1#2
  {
    \@@_draw_literal:x
      { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ lineto }
  }
\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4
  {
     \@@_draw_literal:x
       {
         \dim_to_decimal_in_bp:n {#4} ~ \dim_to_decimal_in_bp:n {#3} ~
         \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~
         moveto~dup~0~rlineto~exch~0~exch~rlineto~neg~0~rlineto~clospath
      }
  }
\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6
  {
    \@@_draw_literal:x
      {
        \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~
        \dim_to_decimal_in_bp:n {#3} ~ \dim_to_decimal_in_bp:n {#4} ~
        \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~
        curveto
      }
 }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:}
% \begin{variable}[aux]{\g_@@_draw_eor_bool}
%    The even-odd rule here can be implemented as a simply switch.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_evenodd_rule:
  { \bool_gset_true:N \g_@@_draw_eor_bool }
\cs_new_protected:Npn \@@_draw_nonzero_rule:
  { \bool_gset_false:N \g_@@_draw_eor_bool }
\bool_new:N \g_@@_draw_eor_bool
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
% \begin{macro}[int]
%   {
%     \@@_draw_closepath:   ,
%     \@@_draw_stroke:      ,
%     \@@_draw_closestroke: ,
%     \@@_draw_fill:        ,
%     \@@_draw_fillstroke:  ,
%     \@@_draw_clip:        ,
%     \@@_draw_discardpath:
%   }
% \begin{variable}[aux]{\g_@@_draw_clip_bool}
%   Unlike PDF, PostScript doesn't track separate colors for strokes and other
%   elements. It is also desirable to have the |clip| keyword after a stroke or
%   fill. To achieve those outcomes, there is some work to do. For color, if a
%   stroke or fill color is defined it is used for the relevant operation, with
%   a graphic scope inserted as required. That does mean that once such a color
%   is set all further uses inside the same scope have to use scoping: see also
%   the color set up functions. For clipping, the required ordering is achieved
%   using a \TeX{} switch. All of the operations end with a new path instruction
%   as they do not terminate (again in contrast to PDF).
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_closepath:
  { \@@_draw_literal:n { closepath } }
\cs_new_protected:Npn \@@_draw_stroke:
  {
    \@@_draw_literal:n { currentdict~/l3sc~known~{gsave~l3sc}~if }
    \@@_draw_literal:n { stroke }
    \@@_draw_literal:n { currentdict~/l3sc~known~{grestore}~if }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_draw_literal:x
          {
            \bool_if:NT \g_@@_draw_eor_bool { eo }
            clip
          }
      }
    \@@_draw_literal:n { newpath }
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
\cs_new_protected:Npn \@@_draw_closestroke:
  {
    \@@_draw_closepath:
    \@@_draw_stroke:
  }
\cs_new_protected:Npn \@@_draw_fill:
  {
    \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
    \@@_draw_literal:x
      {
        \bool_if:NT \g_@@_draw_eor_bool { eo }
        fill
      }
    \@@_draw_literal:n { currentdict~/l3fc~known~{grestore}~if }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_draw_literal:x
          {
            \bool_if:NT \g_@@_draw_eor_bool { eo }
            clip
          }
      }
    \@@_draw_literal:n { newpath }
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
\cs_new_protected:Npn \@@_draw_fillstroke:
  {
    \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
    \@@_draw_literal:x
      {
        \bool_if:NT \g_@@_draw_eor_bool { eo }
        fill
      }
    \@@_draw_literal:n { currentdict~/l3fc~known~{grestore}~if }
    \@@_draw_literal:n { currentdict~/l3sc~known~{gsave~l3sc}~if }
    \@@_draw_literal:n { stroke }
    \@@_draw_literal:n { currentdict~/l3sc~known~{grestore}~if }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_draw_literal:x
          {
            \bool_if:NT \g_@@_draw_eor_bool { eo }
            clip
          }
      }
    \@@_draw_literal:n { newpath }
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
\cs_new_protected:Npn \@@_draw_clip:
  { \bool_gset_true:N \g_@@_draw_clip_bool }
\bool_new:N \g_@@_draw_clip_bool
\cs_new_protected:Npn \@@_draw_discardpath:
  {
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_draw_literal:x
          {
            \bool_if:NT \g_@@_draw_eor_bool { eo }
            clip
          }
      }
    \@@_draw_literal:n { newpath }
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_dash:nn}
% \begin{macro}[aux]{\@@_draw_dash:n}
% \begin{macro}[int]{\@@_draw_linewidth:n}
% \begin{macro}[int]{\@@_draw_miterlimit:n}
% \begin{macro}[int]
%   {
%     \@@_draw_cap_butt:, \@@_draw_cap_round:, \@@_draw_cap_rectangle:,
%     \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel:
%   }
%   Converting paths to output is again a case of mapping directly to
%   PostScript operations.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_dash:nn #1#2
  {
    \@@_draw_literal:x
      {
        [ ~
          \clist_map_function:nN {#1} \@@_draw_dash:n
        ] ~
        \dim_to_decimal_in_bp:n {#2} ~ setdash
      }
  }
\cs_new:Npn \@@_draw_dash:n #1
  { \dim_to_decimal_in_bp:n {#1} ~ }
\cs_new_protected:Npn \@@_draw_linewidth:n #1
  {
    \@@_draw_literal:x
      { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth }
  }
\cs_new_protected:Npn \@@_draw_miterlimit:n #1
  { \@@_draw_literal:x { \fp_eval:n {#1} ~ setmiterlimit } }
\cs_new_protected:Npn \@@_draw_cap_butt:
  { \@@_draw_literal:n { 0 ~ setlinecap } }
\cs_new_protected:Npn \@@_draw_cap_round:
  { \@@_draw_literal:n { 1 ~ setlinecap } }
\cs_new_protected:Npn \@@_draw_cap_rectangle:
  { \@@_draw_literal:n { 2 ~ setlinecap } }
\cs_new_protected:Npn \@@_draw_join_miter:
  { \@@_draw_literal:n { 0 ~ setlinejoin } }
\cs_new_protected:Npn \@@_draw_join_round:
  { \@@_draw_literal:n { 1 ~ setlinejoin } }
\cs_new_protected:Npn \@@_draw_join_bevel:
  { \@@_draw_literal:n { 2 ~ setlinejoin } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[aux]{\_@@_draw_color_reset:}
% \begin{macro}[int]
%   {
%     \@@_draw_color_cmyk:nnnn        ,
%     \@@_draw_color_cmyk_fill:nnnn   ,
%     \@@_draw_color_cmyk_stroke:nnnn
%   }
% \begin{macro}[int]
%   {
%     \@@_draw_color_gray:n        ,
%     \@@_draw_color_gray_fill:n   ,
%     \@@_draw_color_gray_stroke:n
%   }
% \begin{macro}[int]
%   {
%     \@@_draw_color_rgb:nnn        ,
%     \@@_draw_color_rgb_fill:nnn   ,
%     \@@_draw_color_rgb_stroke:nnn
%   }
%   To allow color to be defined for strokes and fills separately and to
%   respect scoping, the data needs to be stored at the PostScript level.
%   We cannot undefine (local) fill/stroke colors once set up but we can
%   set them blank to improve performance slightly.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_color_reset:
  {
    \@@_draw_literal:n { currentdic~/l3fc~known~{ /l3fc~ { } ~def }~if }
    \@@_draw_literal:n { currentdic~/l3sc~known~{ /l3sc~ { } ~def }~if }
  }
\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn #1#2#3#4
  {
    \@@_draw_literal:x
      {
        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
        setcmykcolor ~
      }
    \@@_draw_color_reset:
  }
\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn #1#2#3#4
  {
    \@@_draw_literal:x
      {
        /l3fc ~
          {
            \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
            \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
            setcmykcolor
          } ~
        def
      }
  }
\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
  {
    \__driver_draw_literal:x
      {
        /l3sc ~
          {
            \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
            \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
            setcmykcolor
          } ~
        def
      }
  }
\cs_new_protected:Npn \@@_draw_color_gray:n #1
  {
    \@@_draw_literal:x { fp_eval:n {#1} ~ setgray  }
    \@@_draw_color_reset:
  }
\cs_new_protected:Npn \@@_draw_color_gray_fill:n #1
  { \@@_draw_literal:x { /l3fc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
\cs_new_protected:Npn \@@_draw_color_gray_stroke:n #1
  { \@@_draw_literal:x { /l3sc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
\cs_new_protected:Npn \@@_draw_color_rgb:nnn #1#2#3
  {
    \@@_draw_literal:x
      {
        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
        setrgbcolor
      }
    \@@_draw_color_reset:
  }
\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn #1#2#3
  {
    \@@_draw_literal:x
      {
        /l3fc ~
          {
            \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
            setrgbcolor
          } ~
        def
      }
  }
\cs_new_protected:Npn \@@_draw_color_rgb_stroke:nnn #1#2#3
  {
    \@@_draw_literal:x
      {
        /l3sc ~
          {
            \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
            setrgbcolor
          } ~
        def
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_transformcm:nnnnnn}
%   The first four arguments here are floats (the affine matrix), the last
%   two are a displacement vector. Once again, force evaluation to allow for
%   caching.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_transformcm:nnnnnn #1#2#3#4#5#6
  {
    \@@_draw_literal:x
      {
        [
          \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
          \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
          \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~
        ] ~
        concat
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_hbox:Nnnnnnn}
%   Inside a picture |@beginspecial|/|@endspecial| are active, which is
%   normally a good thing but means that the position and scaling will be off
%   if the box is inserted directly. Instead, we need to reverse the effect of
%   the (normally desirable) shift/scaling within the box. That requires
%   knowing where the reference point for the drawing is: saved as |l3x|/|l3y|
%   at the start of the picture. Transformation here is relative to the
%   drawing origin so has to be done purely in driver code not using \TeX{}
%   offsets.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_hbox:Nnnnnnn #1#2#3#4#5#6#7
  {
    \@@_scope_begin:
    \tex_special:D { ps::[end] }
    \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5} {#6} {#7}
    \tex_special:D { ps::~72~Resolution~div~72~VResolution~div~neg~scale }
    \tex_special:D { ps::~magscale~{1~DVImag~div~dup~scale}~if }
    \tex_special:D { ps::~l3x~neg~l3y~neg~translate }
    \group_begin:
      \box_set_wd:Nn #1 { 0pt }
      \box_set_ht:Nn #1 { 0pt }
      \box_set_dp:Nn #1 { 0pt }
      \box_use:N #1
    \group_end:
    \tex_special:D { ps::[begin] }
    \@@_scope_end:
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvips>
%    \end{macrocode}
%
% \subsection{\texttt{dvisvgm} driver}
%
%    \begin{macrocode}
%<*dvisvgm>
%    \end{macrocode}
%
% \subsubsection{Basics}
%
% \begin{macro}[int]{\@@_literal:n}
%   Unlike the other drivers, the requirements for making SVG files mean
%   that we can't conveniently transform all operations to the current point.
%   That makes life a bit more tricky later as that needs to be accounted for.
%   A new line is added after each call to help to keep the output readable
%   for debugging.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_literal:n #1
  { \tex_special:D { dvisvgm:raw~ #1 { ?nl } } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
%   A scope in SVG terms is slightly different to the other drivers as
%   operations have to be \enquote{tied} to these not simply inside them.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_scope_begin:
  { \@@_literal:n { <g> } }
\cs_new_protected:Npn \@@_scope_end:
  { \@@_literal:n { </g> } }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Driver-specific auxiliaries}
%
% \begin{macro}[int]{\@@_scope_begin:n}
%   In SVG transformations, clips and so on are attached directly to scopes so
%   we need a way or allowing for that. This is rather more useful that
%   \cs{@@_scope_begin:} as a result. No assumptions are made about the nature
%   of the scoped operation(s).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_scope_begin:n #1
  { \@@_literal:n { <g~ #1 > } }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Box operations}
%
% \begin{macro}[int]{\@@_box_use_clip:N}
% \begin{variable}[aux]{\g_@@_clip_path_int}
%   Clipping in SVG is more involved than with other drivers. The first issue
%   is that the clipping path must be defined separately from where it is used,
%   so we need to track how many paths have applied. The naming here uses
%   \texttt{l3cp} as the namespace with a number following. Rather than use
%   a rectangular operation, we define the path manually as this allows it to
%   have a depth: easier than the alternative approach of shifting content
%   up and down using scopes to allow for the depth of the \TeX{} box and
%   keep the reference point the same!
%    \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_clip:N #1
  {
    \int_gincr:N \g_@@_clip_path_int
    \@@_literal:n
      { < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " > }
    \@@_literal:n
      {
        <
          path ~ d =
            "
              M ~ 0 ~
                  \dim_to_decimal:n { -\box_dp:N #1 } ~
              L ~ \dim_to_decimal:n { \box_wd:N #1 } ~
                  \dim_to_decimal:n { -\box_dp:N #1 } ~
              L ~ \dim_to_decimal:n { \box_wd:N #1 }  ~
                  \dim_to_decimal:n { \box_ht:N #1 + \box_dp:N #1 } ~
              L ~ 0 ~
                  \dim_to_decimal:n { \box_ht:N #1 + \box_dp:N #1 } ~
              Z
            "
        />
      }
    \@@_literal:n
      { < /clipPath > }
%    \end{macrocode}
%   In general the SVG set up does not try to transform coordinates to the
%   current point. For clipping we need to do that, so have a transformation
%   here to get us to the right place, and a matching one just before the
%   \TeX{} box is inserted to get things back on track. The clip path needs to
%   come between those two such that if lines up with the current point, as
%   does the \TeX{} box.
%    \begin{macrocode}
    \@@_scope_begin:n
      {
        transform =
          "
            translate ( { ?x } , { ?y } ) ~
            scale ( 1 , -1 )
          "
      }
    \@@_scope_begin:n
      {
        clip-path = "url ( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int ) "
      }
    \@@_scope_begin:n
      {
        transform =
          "
            scale ( -1 , 1 ) ~
            translate ( { ?x } , { ?y } ) ~
            scale ( -1 , -1 )
          "
      }
    \box_use:N #1
    \@@_scope_end:
    \@@_scope_end:
    \@@_scope_end:
%    \skip_horizontal:n { \box_wd:N #1 }
  }
\int_new:N \g_@@_clip_path_int
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
% \begin{macro}[int]{\@@_box_use_rotate:Nn}
%   Rotation has a dedicated operation which includes a centre-of-rotation
%   optional pair. That can be picked up from the driver syntax, so there is
%   no need to worry about the transformation matrix.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
  {
    \@@_scope_begin:n
      {
        transform =
          "
            rotate
            ( \fp_eval:n { round ( -#2 , 5 ) } , ~ { ?x } , ~ { ?y } )
          "
      }
    \box_use:N #1
    \@@_scope_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_box_use_scale:Nnn}
%   In contrast to rotation, we have to account for the current position in this
%   case. That is done using a couple of translations in addition to the scaling
%   (which is therefore done backward with a flip).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
  {
    \@@_scope_begin:n
      {
        transform =
          "
            translate ( { ?x } , { ?y } ) ~
            scale
              (
                \fp_eval:n { round ( -#2 , 5 ) } ,
                \fp_eval:n { round ( -#3 , 5 ) }
              ) ~
            translate ( { ?x } , { ?y } ) ~
            scale ( -1 )
          "
      }
    \hbox_overlap_right:n { \box_use:N #1 }
    \@@_scope_end:
  }
%    \end{macrocode}
% \end{macro}
%
% \subsubsection{Color}
%
% \begin{variable}{\l_@@_current_color_tl}
%   The current color in driver-dependent format: the same as for
%   \texttt{dvips}.
%    \begin{macrocode}
\tl_new:N \l_@@_current_color_tl
\tl_set:Nn \l_@@_current_color_tl { gray~0 }
%<*package>
\AtBeginDocument
  {
    \@ifpackageloaded { color }
      { \tl_set:Nn \l_@@_current_color_tl { \current@color } }
      { }
  }
%</package>
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}[int]{\@@_color_ensure_current:}
% \begin{macro}[aux]{\@@_color_reset:}
%   Directly set the color: same as \texttt{dvips}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_color_ensure_current:
  {
    \tex_special:D { color~push~\l_@@_current_color_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{Drawing}
%
% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x}
%   The same as the more general literal call.
%     \begin{macrocode}
\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:}
%   A drawing needs to be set up such that the co-ordinate system is
%   translated. That is done inside a scope, which as described below
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_begin:
  {
    \@@_draw_scope_begin:
    \@@_draw_scope:n { transform="translate({?x},{?y})~scale(1,-1)" }
  }
\cs_new_protected:Npn \@@_draw_end:
  { \@@_draw_scope_end: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_scope_begin:, \@@_draw_scope_end:}
% \begin{macro}[aux]{\@@_draw_scope:n, \@@_draw_scope:x}
% \begin{variable}[aux]{\g_@@_draw_scope_int, \l_@@_draw_scope_int}
%   Several settings that with other drivers are \enquote{stand alone} have
%   to be given as part of a scope in SVG. As a result, there is a need to
%   provide a mechanism to automatically close these extra scopes. That is
%   done using a dedicated function and a pair of tracking variables. Within
%   each graphics scope we use a global variable to do the work, with a group
%   used to save the value between scopes. The result is that no direct action
%   is needed when creating a scope.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_scope_begin:
  {
    \int_set_eq:NN
      \l_@@_draw_scope_int
      \g_@@_draw_scope_int
    \group_begin:
      \int_gset:Nn \g_@@_draw_scope_int { 0 }
  }
\cs_new_protected:Npn \@@_draw_scope_end:
  {
      \prg_replicate:nn
        { \g_@@_draw_scope_int }
        { \@@_draw_literal:n { </g> } }
    \group_end:
    \int_gset_eq:NN
      \g_@@_draw_scope_int
      \l_@@_draw_scope_int
  }
\cs_new_protected:Npn \@@_draw_scope:n #1
  {
    \@@_draw_literal:n { <g~ #1 > }
    \int_gincr:N \g_@@_draw_scope_int
  }
\cs_generate_variant:Nn \@@_draw_scope:n { x }
\int_new:N \g_@@_draw_scope_int
\int_new:N \l_@@_draw_scope_int
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_moveto:nn, \@@_draw_lineto:nn}
% \begin{macro}[int]{\@@_draw_rectangle:nnnn}
% \begin{macro}[int]{\@@_draw_curveto:nnnnnn}
% \begin{macro}[aux]{\@@_draw_add_to_path:n}
% \begin{variable}[aux]{\g_@@_draw_path_tl}
%   Once again, some work is needed to get path constructs correct. Rather
%   then write the values as they are given, the entire path needs to be
%   collected up before being output in one go. For that we use a dedicated
%   storage routine, which will add spaces as required. Since paths should
%   be fully expanded there is no need to worry about the internal
%   \texttt{x}-type expansion.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_moveto:nn #1#2
  {
    \@@_draw_add_to_path:n
      { M ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} }
  }
\cs_new_protected:Npn \@@_draw_lineto:nn #1#2
  {
    \@@_draw_add_to_path:n
      { L ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} }
  }
\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4
  {
    \@@_draw_add_to_path:n
      {
        M ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2}
        h ~ \dim_to_decimal:n {#3} ~
        v ~ \dim_to_decimal:n {#4} ~
        h ~ \dim_to_decimal:n { -#3 } ~
        Z
      }
  }
\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6
  {
    \@@_draw_add_to_path:n
      {
        C ~
        \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} ~
        \dim_to_decimal:n {#3} ~ \dim_to_decimal:n {#4} ~
        \dim_to_decimal:n {#5} ~ \dim_to_decimal:n {#6}
      }
  }
\cs_new_protected:Npn \@@_draw_add_to_path:n #1
  {
    \tl_gset:Nx \g_@@_draw_path_tl
      {
        \g_@@_draw_path_tl
        \tl_if_empty:NF \g_@@_draw_path_tl { \c_space_tl }
        #1
      }
  }
\tl_new:N \g_@@_draw_path_tl
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:}
%   The fill rules here have to be handled as scopes.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_evenodd_rule:
  { \@@_draw_scope:n { fill-rule="evenodd" } }
\cs_new_protected:Npn \@@_draw_nonzero_rule:
  { \@@_draw_scope:n { fill-rule="nonzero" } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[aux]{\@@_draw_path:n}
% \begin{macro}[int]
%   {
%     \@@_draw_closepath:   ,
%     \@@_draw_stroke:      ,
%     \@@_draw_closestroke: ,
%     \@@_draw_fill:        ,
%     \@@_draw_fillstroke:  ,
%     \@@_draw_clip:        ,
%     \@@_draw_discardpath:
%   }
% \begin{variable}[aux]{\g_@@_draw_clip_bool}
% \begin{variable}[aux]{\g_@@_draw_path_int}
%   Setting fill and stroke effects and doing clipping all has to be done using
%   scopes. This means setting up the various requirements in a shared
%   auxiliary which deals with the bits and pieces. Clipping paths are reused
%   for path drawing: not essential but avoids constructing them twice.
%   Discarding a path needs a separate function as it's not quite the same.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_closepath:
  { \@@_draw_add_to_path:n { Z } }
\cs_new_protected:Npn \@@_draw_path:n #1
  {
    \bool_if:NTF \g_@@_draw_clip_bool
      {
        \int_gincr:N \g_@@_clip_path_int
        \@@_draw_literal:x
          {
            < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " >
              { ?nl }
            <path~d=" \g_@@_draw_path_tl "/> { ?nl }
            < /clipPath > { ? nl }
            <
              use~xlink:href =
                "\c_hash_str l3path \int_use:N \g_@@_path_int " ~
                #1
            />
          }
        \@@_draw_scope:x
          {
            clip-path =
              "url( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int)"
          }
      }
      {
        \@@_draw_literal:x
          { <path ~ d=" \g_@@_draw_path_tl " ~ #1 /> }
      }
    \tl_gclear:N \g_@@_draw_path_tl
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
\int_new:N \g_@@_path_int
\cs_new_protected:Npn \@@_draw_stroke:
  { \@@_draw_path:n { style="fill:none" } }
\cs_new_protected:Npn \@@_draw_closestroke:
  {
    \@@_draw_closepath:
    \@@_draw_stroke:
  }
\cs_new_protected:Npn \@@_draw_fill:
  { \@@_draw_path:n { style="stroke:none" } }
\cs_new_protected:Npn \@@_draw_fillstroke:
  { \@@_draw_path:n { } }
\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
      {
        \int_gincr:N \g_@@_clip_path_int
        \@@_draw_literal:x
          {
            < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " >
              { ?nl }
            <path~d=" \g_@@_draw_path_tl "/> { ?nl }
            < /clipPath >
          }
        \@@_draw_scope:x
          {
            clip-path =
              "url( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int)"
          }
      }
    \tl_gclear:N \g_@@_draw_path_tl
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_dash:nn}
% \begin{macro}[aux]{\@@_draw_dash:n}
% \begin{macro}[aux]{\@@_draw_dash_aux:nn}
% \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:
%   }
%   All of these ideas are properties of scopes in SVG. The only slight
%   complexity is converting the dash array properly (doing any required
%   maths).
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_dash:nn #1#2
  {
    \use:x
      {
        \@@_draw_dash_aux:nn
          { \clist_map_function:nn {#1} \@@_draw_dash:n }
          { \dim_to_decimal:n {#2} }
      }
  }
\cs_new:Npn \@@_draw_dash:n #1
  { , \dim_to_decimal_in_bp:n {#1} }
\cs_new_protected:Npn \@@_draw_dash_aux:nn #1#2
  {
    \@@_draw_scope:x
      {
        stroke-dasharray =
          "
            \tl_if_empty:oTF { \use_none:n #1 }
              { none }
              { \use_none:n #1 }
          " ~
          stroke-offset=" #2 "
      }
  }
\cs_new_protected:Npn \@@_draw_linewidth:n #1
  { \@@_draw_scope:x { stroke-width=" \dim_to_decimal:n {#1} " } }
\cs_new_protected:Npn \@@_draw_miterlimit:n #1
  { \@@_draw_scope:x { stroke-miterlimit=" \fp_eval:n {#1} " } }
\cs_new_protected:Npn \@@_draw_cap_butt:
  { \@@_draw_scope:n { stroke-linecap="butt" } }
\cs_new_protected:Npn \@@_draw_cap_round:
  { \@@_draw_scope:n { stroke-linecap="round" } }
\cs_new_protected:Npn \@@_draw_cap_rectangle:
  { \@@_draw_scope:n { stroke-linecap="square" } }
\cs_new_protected:Npn \@@_draw_join_miter:
  { \@@_draw_scope:n { stroke-linejoin="miter" } }
\cs_new_protected:Npn \@@_draw_join_round:
  { \@@_draw_scope:n { stroke-linejoin="round" } }
\cs_new_protected:Npn \@@_draw_join_bevel:
  { \@@_draw_scope:n { stroke-linejoin="bevel" } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[int]
%   {
%     \@@_draw_color_cmyk:nnnn        ,
%     \@@_draw_color_cmyk_fill:nnnn   ,
%     \@@_draw_color_cmyk_stroke:nnnn
%   }
% \begin{macro}[int]
%   {
%     \@@_draw_color_gray:n        ,
%     \@@_draw_color_gray_fill:n   ,
%     \@@_draw_color_gray_stroke:n
%   }
% \begin{macro}[int]
%   {
%     \@@_draw_color_rgb:nnn        ,
%     \@@_draw_color_rgb_fill:nnn   ,
%     \@@_draw_color_rgb_stroke:nnn
%   }
%   SVG only works with RGB colors, so there is some conversion to
%   do. The values also need to be given as percentages, which means a
%   little more maths.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_color_cmyk_aux:NNnnnnn #1#2#3#4#5#6
  {
    \use:x
      {
        \@@_draw_color_rgb_auxii:nnn
          { \fp_eval:n { -100 * ( (#3) * ( 1 - (#6) ) - 1 ) } }
          { \fp_eval:n { -100 * ( (#4) * ( 1 - (#6) ) + #6 - 1 ) } }
          { \fp_eval:n { -100 * ( (#5) * ( 1 - (#6) ) + #6 - 1 ) } }
      }
      #1 #2
  }
\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn
  { \@@_draw_color_cmyk_aux:NNnnnnn \c_true_bool \c_true_bool }
\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn
  { \@@_draw_color_cmyk_aux:NNnnnnn \c_false_bool \c_true_bool }
\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn
  { \@@_draw_color_cmyk_aux:NNnnnnn \c_true_bool \c_false_bool }
\cs_new_protected:Npn \@@_draw_color_gray_aux:NNn #1#2#3
  {
    \use:x
      {
        \@@_draw_color_gray_aux:nNN
          { \fp_eval:n { 100 * (#3)} }
      }
        #1 #2
  }
\cs_new_protected:Npn \@@_draw_color_gray_aux:nNN #1
  { \@@_draw_color_rgb_auxii:nnnNN {#1} {#1} {#1} }
\cs_generate_variant:Nn \@@_draw_color_gray_aux:nNN { x }
\cs_new_protected:Npn \@@_draw_color_gray:n
  { \@@_draw_color_gray_aux:NNn \c_true_bool \c_true_bool }
\cs_new_protected:Npn \@@_draw_color_gray_fill:n
  { \@@_draw_color_gray_aux:NNn \c_false_bool \c_true_bool }
\cs_new_protected:Npn \@@_draw_color_gray_stroke:n
  { \@@_draw_color_gray_aux:NNn \c_true_bool \c_false_bool }
\cs_new_protected:Npn \@@_draw_color_rgb_auxi:NNnnn #1#2#3#4#5
  {
    \use:x
      {
        \@@_draw_color_rgb_auxii:nnnNN
          { \fp_eval:n { 100 * (#3) } }
          { \fp_eval:n { 100 * (#4) } }
          { \fp_eval:n { 100 * (#5) } }
      }
        #1 #2
  }
\cs_new_protected:Npn \@@_draw_color_rgb_auxii:nnnNN #1#2#3#4#5
  {
    \@@_draw_scope:x
      {
        \bool_if:NT #4
          {
            fill =
             "
               rgb
                 (
                   #1 \c_percent_str ,
                   #2 \c_percent_str ,
                   #3 \c_percent_str
                 )
             "
             \bool_if:NT #5 { ~ }
          }
        \bool_if:NT #5
          {
            stroke =
             "
               rgb
                 (
                   #1 \c_percent_str ,
                   #2 \c_percent_str ,
                   #3 \c_percent_str
                 )
             "
          }
      }
  }
\cs_new_protected:Npn \@@_draw_color_rgb:nnn
  { \@@_draw_color_rgb_auxi:NNnnn \c_true_bool \c_true_bool }
\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn
  { \@@_draw_color_rgb_auxi:NNnnn \c_false_bool \c_true_bool }
\cs_new_protected:Npn \@@_draw_color_rgb_stroke:nnn
  { \@@_draw_color_rgb_auxi:NNnnn \c_true_bool \c_false_bool }
%    \end{macrocode}
% \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_scope:x
      {
       transform =
         "
           matrix
             (
               \fp_eval:n {#1} , \fp_eval:n {#2} ,
               \fp_eval:n {#3} , \fp_eval:n {#4} ,
               \dim_to_decimal:n {#5} , \dim_to_decimal:n {#6}
             )
         "
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_hbox:Nnnnnnn}
%   No special savings can be made here: simply displace the box inside
%   a scope. As there is nothing to re-box, just make the box passed of
%   zero size.
%     \begin{macrocode}
\cs_new_protected:Npn \@@_draw_hbox:Nnnnnnn #1#2#3#4#5#6#7
  {
    \@@_scope_begin:
    \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5} {#6} {#7}
    \@@_literal:n
      {
        < g~
            stroke="none"~
            transform="scale(-1,1)~translate({?x},{?y})~scale(-1,-1)"
        >
      }
    \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:
    \@@_literal:n { </g> }
    \@@_scope_end:
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvisvgm>
%    \end{macrocode}
%
%    \begin{macrocode}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
