% \iffalse meta-comment
%
%% File: l3backend-draw.dtx
%
% Copyright (C) 2019-2026 The LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
% This file is part of the "l3backend bundle" (The Work in LPPL)
% and all files in that bundle must be distributed together.
%
% -----------------------------------------------------------------------
%
% The development version of the bundle can be found at
%
%    https://github.com/latex3/latex3
%
% for those people who are interested.
%
%<*driver>
\documentclass[full,kernel]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{l3backend-draw} package\\ Backend drawing support^^A
% }
%
% \author{^^A
%  The \LaTeX{} Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released 2026-07-20}
%
% \maketitle
%
% \begin{documentation}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3backend-draw} implementation}
%
%    \begin{macrocode}
%<*package>
%<@@=draw>
%    \end{macrocode}
%
% \subsection{\texttt{dvips} backend}
%
%    \begin{macrocode}
%<*dvips>
%    \end{macrocode}
%
% \begin{macro}{\@@_backend_literal:n, \@@_backend_literal:e}
%   The same as literal PostScript: same arguments about positioning apply
%   here.
%    \begin{macrocode}
\cs_new_eq:NN \@@_backend_literal:n \__kernel_backend_literal_postscript:n
\cs_generate_variant:Nn \@@_backend_literal:n { e }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_begin:, \@@_backend_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.
%   As for \pkg{pgf}, we need to save the current point as this is
%   required for box placement. (Note that
%   |@beginspecial|/|@endspecial| forms a backend scope.)
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_begin:
  {
    \@@_backend_literal:n { [begin] }
    \@@_backend_literal:n { /draw.x~currentpoint~/draw.y~exch~def~def }
    \@@_backend_literal:n { @beginspecial }
  }
\cs_new_protected:Npn \@@_backend_end:
  {
    \@@_backend_literal:n { @endspecial }
    \@@_backend_literal:n { [end] }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_scope_begin:, \@@_backend_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 \@@_backend_scope_begin:
  { \@@_backend_literal:n { save } }
\cs_new_protected:Npn \@@_backend_scope_end:
  { \@@_backend_literal:n { restore } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_moveto:nn, \@@_backend_lineto:nn}
% \begin{macro}{\@@_backend_rectangle:nnnn}
% \begin{macro}{\@@_backend_curveto:nnnnnn}
%   Path creation operations mainly resolve directly to PostScript primitive
%   steps, with only the need to convert to \texttt{bp}. Notice that
%   \texttt{e}-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 \@@_backend_moveto:nn #1#2
  {
    \@@_backend_literal:e
      {
        \dim_to_decimal_in_bp:n {#1} ~
        \dim_to_decimal_in_bp:n {#2} ~ moveto
      }
  }
\cs_new_protected:Npn \@@_backend_lineto:nn #1#2
  {
    \@@_backend_literal:e
      {
        \dim_to_decimal_in_bp:n {#1} ~
        \dim_to_decimal_in_bp:n {#2} ~ lineto
      }
  }
\cs_new_protected:Npn \@@_backend_rectangle:nnnn #1#2#3#4
  {
    \@@_backend_literal:e
      {
        \dim_to_decimal_in_bp:n {#4} ~ \dim_to_decimal_in_bp:n {#3} ~
        \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~
        moveto~dup~0~rlineto~exch~0~exch~rlineto~neg~0~rlineto~closepath
      }
  }
\cs_new_protected:Npn \@@_backend_curveto:nnnnnn #1#2#3#4#5#6
  {
    \@@_backend_literal:e
      {
        \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}{\@@_backend_evenodd_rule:, \@@_backend_nonzero_rule:}
% \begin{variable}{\g_@@_draw_eor_bool}
%    The even-odd rule here can be implemented as a simply switch.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_evenodd_rule:
  { \bool_gset_true:N \g_@@_draw_eor_bool }
\cs_new_protected:Npn \@@_backend_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}
%   {
%     \@@_backend_closepath:   ,
%     \@@_backend_stroke:      ,
%     \@@_backend_closestroke: ,
%     \@@_backend_fill:        ,
%     \@@_backend_fillstroke:  ,
%     \@@_backend_clip:        ,
%     \@@_backend_discardpath:
%   }
% \begin{variable}{\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, the
%   stoke color is simple but the fill one has to be inserted by hand. 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 \@@_backend_closepath:
  { \@@_backend_literal:n { closepath } }
\cs_new_protected:Npn \@@_backend_stroke:
  {
    \@@_backend_literal:n { gsave }
    \@@_backend_literal:n { color.sc }
    \@@_backend_literal:n { stroke }
    \@@_backend_literal:n { grestore }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_backend_literal:e
          {
            \bool_if:NT \g_@@_draw_eor_bool { eo }
            clip
          }
      }
    \@@_backend_literal:n { newpath }
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
\cs_new_protected:Npn \@@_backend_closestroke:
  {
    \@@_backend_closepath:
    \@@_backend_stroke:
  }
\cs_new_protected:Npn \@@_backend_fill:
  {
    \@@_backend_literal:e
      {
        \bool_if:NT \g_@@_draw_eor_bool { eo }
        fill
      }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_backend_literal:e
          {
            \bool_if:NT \g_@@_draw_eor_bool { eo }
            clip
          }
      }
    \@@_backend_literal:n { newpath }
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
\cs_new_protected:Npn \@@_backend_fillstroke:
  {
    \@@_backend_literal:e
      {
        \bool_if:NT \g_@@_draw_eor_bool { eo }
        fill
      }
    \@@_backend_literal:n { gsave }
    \@@_backend_literal:n { color.sc }
    \@@_backend_literal:n { stroke }
    \@@_backend_literal:n { grestore }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_backend_literal:e
          {
            \bool_if:NT \g_@@_draw_eor_bool { eo }
            clip
          }
      }
    \@@_backend_literal:n { newpath }
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
\cs_new_protected:Npn \@@_backend_clip:
  { \bool_gset_true:N \g_@@_draw_clip_bool }
\bool_new:N \g_@@_draw_clip_bool
\cs_new_protected:Npn \@@_backend_discardpath:
  {
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_backend_literal:e
          {
            \bool_if:NT \g_@@_draw_eor_bool { eo }
            clip
          }
      }
    \@@_backend_literal:n { newpath }
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
%    \end{macrocode}
% \end{variable}
% \end{macro}
%
% \begin{macro}{\@@_backend_dash_pattern:nn}
% \begin{macro}{\@@_backend_dash:n}
% \begin{macro}{\@@_backend_linewidth:n}
% \begin{macro}{\@@_backend_miterlimit:n}
% \begin{macro}
%   {
%     \@@_backend_cap_butt:, \@@_backend_cap_round:, \@@_backend_cap_rectangle:,
%     \@@_backend_join_miter:, \@@_backend_join_round:, \@@_backend_join_bevel:
%   }
%   Converting paths to output is again a case of mapping directly to
%   PostScript operations.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_dash_pattern:nn #1#2
  {
    \@@_backend_literal:e
      {
        [
          \exp_args:Nf \use:n
            { \clist_map_function:nN {#1} \@@_backend_dash:n }
        ] ~
        \dim_to_decimal_in_bp:n {#2} ~ setdash
      }
  }
\cs_new:Npn \@@_backend_dash:n #1
  { ~ \dim_to_decimal_in_bp:n {#1} }
\cs_new_protected:Npn \@@_backend_linewidth:n #1
  {
    \@@_backend_literal:e
      { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth }
  }
\cs_new_protected:Npn \@@_backend_miterlimit:n #1
  { \@@_backend_literal:n { #1 ~ setmiterlimit } }
\cs_new_protected:Npn \@@_backend_cap_butt:
  { \@@_backend_literal:n { 0 ~ setlinecap } }
\cs_new_protected:Npn \@@_backend_cap_round:
  { \@@_backend_literal:n { 1 ~ setlinecap } }
\cs_new_protected:Npn \@@_backend_cap_rectangle:
  { \@@_backend_literal:n { 2 ~ setlinecap } }
\cs_new_protected:Npn \@@_backend_join_miter:
  { \@@_backend_literal:n { 0 ~ setlinejoin } }
\cs_new_protected:Npn \@@_backend_join_round:
  { \@@_backend_literal:n { 1 ~ setlinejoin } }
\cs_new_protected:Npn \@@_backend_join_bevel:
  { \@@_backend_literal:n { 2 ~ setlinejoin } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_transform:nnnn}
% \begin{macro}{\@@_backend_shift:nn}
%   In \texttt{dvips}, keeping the transformations in line with the engine
%   is unfortunately not possible for scaling and rotations: even if we
%   decompose the matrix into those operations, there is still no backend
%   tracking (\emph{cf.}~\texttt{dvipdfmx}/\XeTeX{}). Thus we take the shortest
%   path available and simply dump the matrix as given.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_transform:nnnn #1#2#3#4
  {
    \@@_backend_literal:n
      { [ #1 ~ #2 ~ #3 ~ #4 ~ 0 ~ 0 ] ~ concat }
  }
\cs_new_protected:Npn \@@_backend_shift:nn #1#2
  {
    \@@_backend_literal:n
      { [ 1 ~ 0 ~ 0 ~ 1 ~ #1 ~ #2 ] ~ concat }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_box_use:Nnnnn}
%   Inside a picture |@beginspecial|/|@endspecial| are active, which is
%   normally a good thing but means that the position and scaling would be off
%   if the box was inserted directly. To deal with that, there are a number of
%   possible approaches. A previous implementation suggested by Tom Rokici
%   used |@endspecial|/|@beginspecial|. This avoids needing internals of
%   \texttt{dvips}, but fails if there the box is used inside a scope
%   (see \url{https://github.com/latex3/latex3/issues/1504}). Instead,
%   we use the same method as \pkg{pgf}, which means tracking the position
%   at the PostScript level. Also note that using |@endspecial| would
%   close the scope it creates, meaning that after a box insertion, any
%   local changes would be lost.  Keeping \texttt{dvips} on track is
%   non-trivial, hence the |[begin]|/|[end]| pair before the
%   |save| and around the |restore|.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_box_use:Nnnnn #1#2#3#4#5
  {
    \@@_backend_literal:n { save }
    \@@_backend_literal:n { 72~Resolution~div~72~VResolution~div~neg~scale }
    \@@_backend_literal:n { magscale { 1~DVImag~div~dup~scale } if }
    \@@_backend_literal:n { draw.x~neg~draw.y~neg~translate }
    \@@_backend_literal:n { [end] }
    \@@_backend_literal:n { [begin] }
    \@@_backend_literal:n { save }
    \@@_backend_literal:n { currentpoint }
    \@@_backend_literal:n { currentpoint~translate }
    \@@_backend_transform:nnnn { 1 } { 0 } { 0 } { -1 }
    \@@_backend_transform:nnnn {#2} {#3} {#4} {#5}
    \@@_backend_transform:nnnn { 1 } { 0 } { 0 } { -1 }
    \@@_backend_literal:n { neg~exch~neg~exch~translate }
    \@@_backend_literal:n { [end] }
    \hbox_overlap_right:n { \box_use:N #1 }
    \@@_backend_literal:n { [begin] }
    \@@_backend_literal:n { restore }
    \@@_backend_literal:n { [end] }
    \@@_backend_literal:n { [begin] }
    \@@_backend_literal:n { restore }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvips>
%    \end{macrocode}
%
% \subsection{\LuaTeX{}, \pdfTeX{}, \texttt{dvipdfmx} and \XeTeX{}}
%
% \LuaTeX{}, \pdfTeX{}, \texttt{dvipdfmx} and \XeTeX{} directly produce PDF output
% and understand a shared set of specials for drawing commands.
%
%    \begin{macrocode}
%<*dvipdfmx|luatex|pdftex|xetex>
%    \end{macrocode}
%
% \subsubsection{Drawing}
%
% \begin{macro}{\@@_backend_literal:n, \@@_backend_literal:e}
%   Pass data through using a dedicated interface.
%    \begin{macrocode}
\cs_new_eq:NN \@@_backend_literal:n \__kernel_backend_literal_pdf:n
\cs_new_eq:NN \@@_backend_literal:e \__kernel_backend_literal_pdf:e
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_begin:, \@@_backend_end:}
%   No special requirements here, so simply set up a drawing scope.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_begin:
  { \@@_backend_scope_begin: }
\cs_new_protected:Npn \@@_backend_end:
  { \@@_backend_scope_end: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_scope_begin:, \@@_backend_scope_end:}
%   Use the backend-level scope mechanisms.
%    \begin{macrocode}
\cs_new_eq:NN \@@_backend_scope_begin: \__kernel_backend_scope_begin:
\cs_new_eq:NN \@@_backend_scope_end: \__kernel_backend_scope_end:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_moveto:nn, \@@_backend_lineto:nn}
% \begin{macro}{\@@_backend_curveto:nnnnnn}
% \begin{macro}{\@@_backend_rectangle:nnnn}
%   Path creation operations all resolve directly to PDF primitive steps, with
%   only the need to convert to \texttt{bp}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_moveto:nn #1#2
  {
    \@@_backend_literal:e
      { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ m }
  }
\cs_new_protected:Npn \@@_backend_lineto:nn #1#2
  {
    \@@_backend_literal:e
      { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ l }
  }
\cs_new_protected:Npn \@@_backend_curveto:nnnnnn #1#2#3#4#5#6
  {
    \@@_backend_literal:e
      {
        \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 \@@_backend_rectangle:nnnn #1#2#3#4
  {
    \@@_backend_literal:e
      {
        \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}{\@@_backend_evenodd_rule:, \@@_backend_nonzero_rule:}
% \begin{variable}{\g_@@_draw_eor_bool}
%    The even-odd rule here can be implemented as a simply switch.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_evenodd_rule:
  { \bool_gset_true:N \g_@@_draw_eor_bool }
\cs_new_protected:Npn \@@_backend_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}
%   {
%     \@@_backend_closepath:   ,
%     \@@_backend_stroke:      ,
%     \@@_backend_closestroke: ,
%     \@@_backend_fill:        ,
%     \@@_backend_fillstroke:  ,
%     \@@_backend_clip:        ,
%     \@@_backend_discardpath:
%   }
%   Converting paths to output is again a case of mapping directly to
%   PDF operations.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_closepath:
  { \@@_backend_literal:n { h } }
\cs_new_protected:Npn \@@_backend_stroke:
  { \@@_backend_literal:n { S } }
\cs_new_protected:Npn \@@_backend_closestroke:
  { \@@_backend_literal:n { s } }
\cs_new_protected:Npn \@@_backend_fill:
  {
    \@@_backend_literal:e
      { f \bool_if:NT \g_@@_draw_eor_bool * }
  }
\cs_new_protected:Npn \@@_backend_fillstroke:
  {
    \@@_backend_literal:e
      { B \bool_if:NT \g_@@_draw_eor_bool * }
  }
\cs_new_protected:Npn \@@_backend_clip:
  {
    \@@_backend_literal:e
      { W \bool_if:NT \g_@@_draw_eor_bool * }
  }
\cs_new_protected:Npn \@@_backend_discardpath:
  { \@@_backend_literal:n { n } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_dash_pattern:nn}
% \begin{macro}{\@@_backend_dash:n}
% \begin{macro}{\@@_backend_linewidth:n}
% \begin{macro}{\@@_backend_miterlimit:n}
% \begin{macro}
%   {
%     \@@_backend_cap_butt:, \@@_backend_cap_round:, \@@_backend_cap_rectangle:,
%     \@@_backend_join_miter:, \@@_backend_join_round:, \@@_backend_join_bevel:
%   }
%   Converting paths to output is again a case of mapping directly to
%   PDF operations.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_dash_pattern:nn #1#2
  {
    \@@_backend_literal:e
      {
        [
          \exp_args:Nf \use:n
            { \clist_map_function:nN {#1} \@@_backend_dash:n }
        ] ~
        \dim_to_decimal_in_bp:n {#2} ~ d
      }
  }
\cs_new:Npn \@@_backend_dash:n #1
  { ~ \dim_to_decimal_in_bp:n {#1} }
\cs_new_protected:Npn \@@_backend_linewidth:n #1
  {
    \@@_backend_literal:e
      { \dim_to_decimal_in_bp:n {#1} ~ w }
  }
\cs_new_protected:Npn \@@_backend_miterlimit:n #1
  { \@@_backend_literal:e { #1 ~ M } }
\cs_new_protected:Npn \@@_backend_cap_butt:
  { \@@_backend_literal:n { 0 ~ J } }
\cs_new_protected:Npn \@@_backend_cap_round:
  { \@@_backend_literal:n { 1 ~ J } }
\cs_new_protected:Npn \@@_backend_cap_rectangle:
  { \@@_backend_literal:n { 2 ~ J } }
\cs_new_protected:Npn \@@_backend_join_miter:
  { \@@_backend_literal:n { 0 ~ j } }
\cs_new_protected:Npn \@@_backend_join_round:
  { \@@_backend_literal:n { 1 ~ j } }
\cs_new_protected:Npn \@@_backend_join_bevel:
  { \@@_backend_literal:n { 2 ~ j } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_transform:nnnn}
% \begin{macro}{\@@_backend_transform_aux:nnnn}
% \begin{macro}{\@@_backend_shift:nn}
%   Another split here between \LuaTeX{}/pdfTeX{} and \texttt{dvipdfmx}/\XeTeX{}.
%   In the former, we have a direct method to maintain alignment: the backend
%   can use a matrix itself. For \texttt{dvipdfmx}/\XeTeX{}, we can to decompose the
%   matrix into rotations and a scaling, then use those operations as they
%   are handled by the backend. (There is backend support for matrix operations in
%   \texttt{dvipdfmx}/\XeTeX{}, but as a matched pair so not suitable for the
%   \enquote{stand alone} transformation set up here.) The specials used here
%   are from \texttt{xdvipdfmx} originally: they are well-tested, but probably
%   equivalent to the \texttt{pdf:} versions! As working out the rotation is
%   relatively expensive, we optimize for the case where there is only a
%   scaling.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_transform:nnnn #1#2#3#4
  {
%<*luatex|pdftex>
    \__kernel_backend_matrix:n { #1 ~ #2 ~ #3 ~ #4 }
%</luatex|pdftex>
%<*dvipdfmx|xetex>
    \str_if_eq:nnTF { #2 ~ #3 } { 0 ~ 0 }
      {
        \__kernel_backend_literal:n { x:rotate~0 }
        \__kernel_backend_literal:n { x:scale~#1~#4 }
        \__kernel_backend_literal:n { x:rotate~0 }
      }
      {
        \@@_backend_transform_decompose:nnnnN {#1} {#2} {#3} {#4}
          \@@_backend_transform_aux:nnnn
      }
%</dvipdfmx|xetex>
  }
%<*dvipdfmx|xetex>
\cs_new_protected:Npn \@@_backend_transform_aux:nnnn #1#2#3#4
  {
    \__kernel_backend_literal:e
      {
        x:rotate~
        \fp_compare:nNnTF {#1} = \c_zero_fp
          { 0 }
          { \fp_eval:n { round ( -#1 , 5 ) } }
      }
    \__kernel_backend_literal:e
      {
        x:scale~
        \fp_eval:n { round ( #2 , 5 ) } ~
        \fp_eval:n { round ( #3 , 5 ) }
      }
    \__kernel_backend_literal:e
      {
        x:rotate~
        \fp_compare:nNnTF {#4} = \c_zero_fp
          { 0 }
          { \fp_eval:n { round ( -#4 , 5 ) } }
      }
  }
%</dvipdfmx|xetex>
%    \end{macrocode}
%   Much less complex for a shift: this is deliberately not tracked by the
%   engine (we would otherwise do stuff in \TeX{}), so use the same approach
%   for all PDF-based routes.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_shift:nn #1#2
  {
    \@@_backend_literal:n
      { 1 ~ 0 ~ 0 ~ 1 ~ #1 ~ #2 ~ cm }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_transform_decompose:nnnnN}
% \begin{macro}
%   {
%     \@@_backend_transform_decompose_auxi:nnnnN,
%     \@@_backend_transform_decompose_auxii:nnnnN,
%     \@@_backend_transform_decompose_auxiii:nnnnN,
%   }
%   Internally, transformations for drawing are tracked as a matrix. Not all
%   engines provide a way of dealing with this: if we use a raw matrix, the
%   engine looses track of positions (for example for hyperlinks), and this is
%   not desirable. They do, however, allow us to track rotations and scalings.
%   Luckily, we can decompose any (two-dimensional) matrix into two rotations
%   and a single scaling:
%   \[
%     \begin{bmatrix}
%         A & B \\ C & D
%     \end{bmatrix}
%     =
%     \begin{bmatrix}
%       \cos\beta & \sin\beta \\ -\sin\beta & \cos\beta
%     \end{bmatrix}
%     \begin{bmatrix}
%       w_{1} & 0 \\ 0 & w_{2}
%     \end{bmatrix}
%     \begin{bmatrix}
%       \cos\gamma & \sin\gamma \\ -\sin\gamma & \cos\gamma
%     \end{bmatrix}
%   \]
%   The parent matrix can be converted to
%   \[
%     \begin{bmatrix}
%       A & B \\ C & D
%     \end{bmatrix}
%      =
%     \begin{bmatrix}
%       E & H \\-H & E
%     \end{bmatrix}
%     +
%     \begin{bmatrix}
%       F & G \\ G & -F
%     \end{bmatrix}
%   \]
%   From these, we can find that
%   \begin{align*}
%     \frac{w_{1} + w_{2}}{2} &= \sqrt{E^{2} + H^{2}} \\
%     \frac{w_{1} - w_{2}}{2} &= \sqrt{F^{2} + G^{2}} \\
%     \gamma - \beta &= \tan^{-1}(G/F) \\
%     \gamma + \beta &= \tan^{-1}(H/E)
%   \end{align*}
%   at which point we just have to do various pieces of re-arrangement to
%   get all of the values. (See J.~Blinn, \emph{IEEE Comput.\ Graph.\ Appl.},
%   1996, \textbf{16}, 82--88.) There is one wrinkle: the PostScript (and PDF)
%   way of specifying a transformation matrix exchanges where one would
%   normally expect $B$ and $C$ to be.
%    \begin{macrocode}
%<*dvipdfmx|xetex>
\cs_new_protected:Npn \@@_backend_transform_decompose:nnnnN #1#2#3#4#5
  {
    \use:e
      {
        \@@_backend_transform_decompose_auxi:nnnnN
          { \fp_eval:n { (#1 + #4) / 2 } }
          { \fp_eval:n { (#1 - #4) / 2 } }
          { \fp_eval:n { (#3 + #2) / 2 } }
          { \fp_eval:n { (#3 - #2) / 2 } }
      }
        #5
  }
\cs_new_protected:Npn \@@_backend_transform_decompose_auxi:nnnnN #1#2#3#4#5
  {
    \use:e
      {
        \@@_backend_transform_decompose_auxii:nnnnN
          { \fp_eval:n { 2 * sqrt ( #1 * #1 + #4 * #4 ) } }
          { \fp_eval:n { 2 * sqrt ( #2 * #2 + #3 * #3 ) } }
          { \fp_eval:n { atand ( #3 , #2 ) } }
          { \fp_eval:n { atand ( #4 , #1 ) } }
      }
        #5
  }
\cs_new_protected:Npn \@@_backend_transform_decompose_auxii:nnnnN #1#2#3#4#5
  {
    \use:e
      {
        \@@_backend_transform_decompose_auxiii:nnnnN
          { \fp_eval:n { ( #4 - #3 ) / 2 } }
          { \fp_eval:n { ( #1 + #2 ) / 2 } }
          { \fp_eval:n { ( #1 - #2 ) / 2 } }
          { \fp_eval:n { ( #4 + #3 ) / 2 } }
      }
        #5
  }
\cs_new_protected:Npn \@@_backend_transform_decompose_auxiii:nnnnN #1#2#3#4#5
  {
    \fp_compare:nNnTF { abs( #2 ) } > { abs ( #3 ) }
      { #5 {#1} {#2} {#3} {#4} }
      { #5 {#1} {#3} {#2} {#4} }
  }
%</dvipdfmx|xetex>
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_box_use:Nnnnn}
%   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 \@@_backend_box_use:Nnnnn #1#2#3#4#5
  {
    \__kernel_backend_scope_begin:
%<*luatex|pdftex>
    \__kernel_backend_matrix:n { #2 ~ #3 ~ #4 ~ #5 }
%</luatex|pdftex>
%<*dvipdfmx|xetex>
    \__kernel_backend_literal:n
      { pdf:btrans~matrix~ #2 ~ #3 ~ #4 ~ #5 ~ 0 ~ 0 }
%</dvipdfmx|xetex>
    \hbox_overlap_right:n { \box_use:N #1 }
%<*dvipdfmx|xetex>
    \__kernel_backend_literal:n { pdf:etrans }
%</dvipdfmx|xetex>
    \__kernel_backend_scope_end:
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvipdfmx|luatex|pdftex|xetex>
%    \end{macrocode}
%
% \subsection{\texttt{dvisvgm} backend}
%
%    \begin{macrocode}
%<*dvisvgm>
%    \end{macrocode}
%
% \begin{macro}{\@@_backend_literal:n, \@@_backend_literal:e}
%   The same as the more general literal call.
%    \begin{macrocode}
\cs_new_eq:NN \@@_backend_literal:n \__kernel_backend_literal_svg:n
\cs_generate_variant:Nn \@@_backend_literal:n { e }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_scope_begin:, \@@_backend_scope_end:}
%   Use the backend-level scope mechanisms.
%    \begin{macrocode}
\cs_new_eq:NN \@@_backend_scope_begin: \__kernel_backend_scope_begin:
\cs_new_eq:NN \@@_backend_scope_end: \__kernel_backend_scope_end:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_begin:, \@@_backend_end:}
%   A drawing needs to be set up such that the coordinate system is
%   translated. That is done inside a scope, which as described below
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_begin:
  {
    \__kernel_backend_scope_begin:
    \__kernel_backend_scope:n { transform="translate({?x},{?y})~scale(1,-1)" }
  }
\cs_new_eq:NN \@@_backend_end: \__kernel_backend_scope_end:
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_moveto:nn, \@@_backend_lineto:nn}
% \begin{macro}{\@@_backend_rectangle:nnnn}
% \begin{macro}{\@@_backend_curveto:nnnnnn}
% \begin{macro}{\@@_backend_add_to_path:n}
% \begin{variable}{\g_@@_backend_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 adds spaces as required. Since paths should
%   be fully expanded there is no need to worry about the internal
%   \texttt{e}-type expansion.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_moveto:nn #1#2
  {
    \@@_backend_add_to_path:n
      { M ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} }
  }
\cs_new_protected:Npn \@@_backend_lineto:nn #1#2
  {
    \@@_backend_add_to_path:n
      { L ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} }
  }
\cs_new_protected:Npn \@@_backend_rectangle:nnnn #1#2#3#4
  {
    \@@_backend_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 \@@_backend_curveto:nnnnnn #1#2#3#4#5#6
  {
    \@@_backend_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 \@@_backend_add_to_path:n #1
  {
    \tl_gset:Ne \g_@@_backend_path_tl
      {
        \g_@@_backend_path_tl
        \tl_if_empty:NF \g_@@_backend_path_tl { \c_space_tl }
        #1
      }
  }
\tl_new:N \g_@@_backend_path_tl
%    \end{macrocode}
% \end{variable}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_evenodd_rule:, \@@_backend_nonzero_rule:}
%   The fill rules here have to be handled as scopes.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_evenodd_rule:
  { \__kernel_backend_scope:n { fill-rule="evenodd" } }
\cs_new_protected:Npn \@@_backend_nonzero_rule:
  { \__kernel_backend_scope:n { fill-rule="nonzero" } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_path:n}
% \begin{macro}
%   {
%     \@@_backend_closepath:   ,
%     \@@_backend_stroke:      ,
%     \@@_backend_closestroke: ,
%     \@@_backend_fill:        ,
%     \@@_backend_fillstroke:  ,
%     \@@_backend_clip:        ,
%     \@@_backend_discardpath:
%   }
% \begin{variable}{\g_@@_draw_clip_bool}
% \begin{variable}{\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 \@@_backend_closepath:
  { \@@_backend_add_to_path:n { Z } }
\cs_new_protected:Npn \@@_backend_path:n #1
  {
    \bool_if:NTF \g_@@_draw_clip_bool
      {
        \int_gincr:N \g__kernel_clip_path_int
        \@@_backend_literal:e
          {
            < clipPath~id = " l3cp \int_use:N \g__kernel_clip_path_int " >
              { ?nl }
            <path~d=" \g_@@_backend_path_tl "/> { ?nl }
            < /clipPath > { ? nl }
            <
              use~xlink:href =
                "\c_hash_str l3path \int_use:N \g_@@_backend_path_int " ~
                #1
            />
          }
        \__kernel_backend_scope:e
          {
            clip-path =
              "url( \c_hash_str l3cp \int_use:N \g__kernel_clip_path_int)"
          }
      }
      {
        \@@_backend_literal:e
          { <path ~ d=" \g_@@_backend_path_tl " ~ #1 /> }
      }
    \tl_gclear:N \g_@@_backend_path_tl
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
\int_new:N \g_@@_backend_path_int
\cs_new_protected:Npn \@@_backend_stroke:
  { \@@_backend_path:n { style="fill:none" } }
\cs_new_protected:Npn \@@_backend_closestroke:
  {
    \@@_backend_closepath:
    \@@_backend_stroke:
  }
\cs_new_protected:Npn \@@_backend_fill:
  { \@@_backend_path:n { style="stroke:none" } }
\cs_new_protected:Npn \@@_backend_fillstroke:
  { \@@_backend_path:n { } }
\cs_new_protected:Npn \@@_backend_clip:
  { \bool_gset_true:N \g_@@_draw_clip_bool }
\bool_new:N \g_@@_draw_clip_bool
\cs_new_protected:Npn \@@_backend_discardpath:
  {
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \int_gincr:N \g__kernel_clip_path_int
        \@@_backend_literal:e
          {
            < clipPath~id = " l3cp \int_use:N \g__kernel_clip_path_int " >
              { ?nl }
            <path~d=" \g_@@_backend_path_tl "/> { ?nl }
            < /clipPath >
          }
        \__kernel_backend_scope:e
          {
            clip-path =
              "url( \c_hash_str l3cp \int_use:N \g__kernel_clip_path_int)"
          }
      }
    \tl_gclear:N \g_@@_backend_path_tl
    \bool_gset_false:N \g_@@_draw_clip_bool
  }
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_dash_pattern:nn}
% \begin{macro}{\@@_backend_dash:n}
% \begin{macro}{\@@_backend_dash_aux:nn}
% \begin{macro}{\@@_backend_linewidth:n}
% \begin{macro}{\@@_backend_miterlimit:n}
% \begin{macro}
%   {
%     \@@_backend_cap_butt:, \@@_backend_cap_round:, \@@_backend_cap_rectangle:,
%     \@@_backend_join_miter:, \@@_backend_join_round:, \@@_backend_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 \@@_backend_dash_pattern:nn #1#2
  {
    \use:e
      {
        \@@_backend_dash_aux:nn
          { \clist_map_function:nN {#1} \@@_backend_dash:n }
          { \dim_to_decimal:n {#2} }
      }
  }
\cs_new:Npn \@@_backend_dash:n #1
  { , \dim_to_decimal_in_bp:n {#1} }
\cs_new_protected:Npn \@@_backend_dash_aux:nn #1#2
  {
    \__kernel_backend_scope:e
      {
        stroke-dasharray =
          "
            \tl_if_empty:nTF {#1}
              { none }
              { \use_none:n #1 }
          " ~
          stroke-offset=" #2 "
      }
  }
\cs_new_protected:Npn \@@_backend_linewidth:n #1
  { \__kernel_backend_scope:e { stroke-width=" \dim_to_decimal:n {#1} " } }
\cs_new_protected:Npn \@@_backend_miterlimit:n #1
  { \__kernel_backend_scope:e { stroke-miterlimit=" #1 " } }
\cs_new_protected:Npn \@@_backend_cap_butt:
  { \__kernel_backend_scope:n { stroke-linecap="butt" } }
\cs_new_protected:Npn \@@_backend_cap_round:
  { \__kernel_backend_scope:n { stroke-linecap="round" } }
\cs_new_protected:Npn \@@_backend_cap_rectangle:
  { \__kernel_backend_scope:n { stroke-linecap="square" } }
\cs_new_protected:Npn \@@_backend_join_miter:
  { \__kernel_backend_scope:n { stroke-linejoin="miter" } }
\cs_new_protected:Npn \@@_backend_join_round:
  { \__kernel_backend_scope:n { stroke-linejoin="round" } }
\cs_new_protected:Npn \@@_backend_join_bevel:
  { \__kernel_backend_scope:n { stroke-linejoin="bevel" } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_transform:nnnn}
% \begin{macro}{\@@_backend_shift:nn}
%   The four arguments here are floats (the affine matrix), the last
%   two are a displacement vector.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_transform:nnnn #1#2#3#4
  {
    \__kernel_backend_scope:n
      {
        transform =
          " matrix ( #1 , #2 , #3 , #4 , 0pt , 0pt ) "
      }
  }
\cs_new_protected:Npn \@@_backend_shift:nn #1#2
  {
    \__kernel_backend_scope:n
      {
        transform =
          " matrix ( 1 , 0 , 0 , 1 ,  #1pt , #2pt ) "
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_box_use:Nnnnn}
%   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 \@@_backend_box_use:Nnnnn #1#2#3#4#5
  {
    \__kernel_backend_scope_begin:
    \@@_backend_transform:nnnn {#2} {#3} {#4} {#5}
    \__kernel_backend_literal_svg:n
      {
        < g~
            stroke="none"~
            transform="scale(-1,1)~translate({?x},{?y})~scale(-1,-1)"
        >
      }
    \box_set_wd:Nn #1 { 0pt }
    \box_set_ht:Nn #1 { 0pt }
    \box_set_dp:Nn #1 { 0pt }
    \box_use:N #1
    \__kernel_backend_literal_svg:n { </g> }
    \__kernel_backend_scope_end:
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvisvgm>
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
