% \iffalse meta-comment
%
%% File: l3backend-draw.dtx
%
% Copyright (C) 2019 The LaTeX3 Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
% This file is part of the "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 \textsf{l3backend-draw} package\\ Backend drawing support^^A
% }
%
% \author{^^A
%  The \LaTeX3 Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released 2019-10-11}
%
% \maketitle
%
% \begin{documentation}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3backend-draw} Implementation}
%
%    \begin{macrocode}
%<*initex|package>
%<@@=draw>
%    \end{macrocode}
%
% \subsection{\texttt{dvips} backend}
%
%    \begin{macrocode}
%<*dvips>
%    \end{macrocode}
%
% \begin{macro}{\@@_backend_literal:n, \@@_backend_literal:x}
%   The same as literal PostScript: same arguments about positioning apply
%   her.
%    \begin{macrocode}
\cs_new_eq:NN \@@_backend_literal:n \__kernel_backend_literal_postscript:n
\cs_generate_variant:Nn \@@_backend_literal:n { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_begin:, \@@_backend_end:}
% \begin{macro}{color.fc}
%   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 definition of |/color.fc| deals with fill
%   color in paths. In contrast to \pkg{pgf}, we don't save the current point:
%   discussion with Tom Rokici suggested a better way to handle the necessary
%   translations (see \cs{@@_backend_box_use:Nnnnn}). (Note that
%   |@beginspecial|/|@endspecial| forms a backend scope.) The  |[begin]|/^^A
%   |[end]| lines are handled differently from the rest as they are
%   conceptually different: not really drawing literals but instructions to
%   \texttt{dvips} itself.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_begin:
  {
    \__kernel_backend_literal:n { ps::[begin] }
    \@@_backend_literal:n { @beginspecial }
    \@@_backend_literal:n { SDict ~ begin ~ /color.fc ~ { } ~ def ~ end }
  }
\cs_new_protected:Npn \@@_backend_end:
  {
    \@@_backend_literal:n { @endspecial }
    \__kernel_backend_literal:n { ps::[end] }
  }
%    \end{macrocode}
% \end{macro}
% \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{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 \@@_backend_moveto:nn #1#2
  {
    \@@_backend_literal:x
      {
        \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:x
      {
        \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:x
       {
         \dim_to_decimal_in_bp:n {#4} ~ \dim_to_decimal_in_bp:n {#3} ~
         \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~
         moveto~dup~0~rlineto~exch~0~exch~rlineto~neg~0~rlineto~closepath
      }
  }
\cs_new_protected:Npn \@@_backend_curveto:nnnnnn #1#2#3#4#5#6
  {
    \@@_backend_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}{\@@_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 { stroke }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_backend_literal:x
          {
            \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:n { gsave }
    \@@_backend_literal:n { color.fc }
    \@@_backend_literal:x
      {
        \bool_if:NT \g_@@_draw_eor_bool { eo }
        fill
      }
    \@@_backend_literal:n { grestore }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_backend_literal:x
          {
            \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:n { gsave }
    \@@_backend_literal:n { color.fc }
    \@@_backend_literal:x
      {
        \bool_if:NT \g_@@_draw_eor_bool { eo }
        fill
      }
    \@@_backend_literal:n { grestore }
    \@@_backend_literal:n { stroke }
    \bool_if:NT \g_@@_draw_clip_bool
      {
        \@@_backend_literal:x
          {
            \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:x
          {
            \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:x
      {
        [ 
          \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:x
      { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth }
  }
\cs_new_protected:Npn \@@_backend_miterlimit:n #1
  { \@@_backend_literal:x { \fp_eval: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_color_fill_cmyk:nnnn   ,
%     \@@_backend_color_stroke_cmyk:nnnn
%   }
% \begin{macro}
%   {
%     \@@_backend_color_fill_gray:n   ,
%     \@@_backend_color_stroke_gray:n
%   }
% \begin{macro}
%   {
%     \@@_backend_color_fill_rgb:nnn   ,
%     \@@_backend_color_stroke_rgb:nnn
%   }
% \begin{macro}
%   {
%     \@@_backend_color_fill:n, \@@_backend_color_fill:x,
%     \@@_backend_color_stroke:n, \@@_backend_color_stroke:x
%   }
%   For \texttt{dvips}, we can use the standard color stack to deal with
%   stroke color, but for fills have to switch to raw PostScript. This is
%   thus not handled by the stack, but the context is very restricted. See
%   also how fills are implemented.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_color_fill_cmyk:nnnn #1#2#3#4
  {
    \@@_backend_color_fill:x
      {
        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
        setcmykcolor
      }
  }
\cs_new_protected:Npn \@@_backend_color_stroke_cmyk:nnnn #1#2#3#4
  {
    \@@_backend_color_stroke:x
      {
        cmyk ~
        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
        \fp_eval:n {#3} ~ \fp_eval:n {#4}
      }
  }
\cs_new_protected:Npn \@@_backend_color_fill_gray:n #1
  { \@@_backend_color_fill:x { \fp_eval:n {#1} ~ setgray } }
\cs_new_protected:Npn \@@_backend_color_stroke_gray:n #1
  { \@@_backend_color_stroke:x { gray ~ \fp_eval:n {#1} } }
\cs_new_protected:Npn \@@_backend_color_fill_rgb:nnn #1#2#3
  {
    \@@_backend_color_fill:x
      { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ setrgbcolor }
  }
\cs_new_protected:Npn \@@_backend_color_stroke_rgb:nnn #1#2#3
  {
    \@@_backend_color_stroke:x
      { rgb ~ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} }
  }
\cs_new_protected:Npn \@@_backend_color_fill:n #1
  { 
    \__kernel_backend_postscript:n
      { /color.fc ~ { #1 } ~ def }
  }
\cs_generate_variant:Nn \@@_backend_color_fill:n { x }
\cs_new_protected:Npn \@@_backend_color_stroke:n #1
  {
    \__kernel_backend_literal:n { color~push~#1 } 
    \group_insert_after:N \@@_color_reset:
  }
\cs_generate_variant:Nn \@@_backend_color_stroke:n { x }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_cm:nnnn}
%   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{(x)dvipdfmx}). Thus we take the shortest
%   path available and simply dump the matrix as given.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_cm:nnnn #1#2#3#4
  {
    \@@_backend_literal:n
      {
        [
          \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
          \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
          0 ~ 0
        ] ~
        concat
      }
  }
%    \end{macrocode}
% \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. The implementation here was suggested by Tom Rokici
%   (author of \texttt{dvips}). We end the current special placement, then
%   set the current point with a literal |[begin]|. As for general
%   literals, we then use the stack to store the current point and move to
%   it. To insert the required transformation, we have to flip the $y$-axis,
%   once before and once after it. Then we get back to the \TeX{} reference
%   point to insert our content. The clean up has to happen in the right
%   places, hence the |[begin]|/|[end]| pair around |restore|. Finally,
%   we can return to \enquote{normal} drawing mode. Notice that the set up
%   here is very similar to that in \cs{@@_align_currentpoint_\ldots}, but
%   the ordering of saving and restoring is different (intermixed).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_box_use:Nnnnn #1#2#3#4#5
  {
    \@@_backend_literal:n { @endspecial }
    \@@_backend_literal:n { [end] }
    \@@_backend_literal:n { [begin] }
    \@@_backend_literal:n { save }
    \@@_backend_literal:n { currentpoint }
    \@@_backend_literal:n { currentpoint~translate }
    \@@_backend_cm:nnnn { 1 } { 0 } { 0 } { -1 }
    \@@_backend_cm:nnnn {#2} {#3} {#4} {#5}
    \@@_backend_cm: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 { @beginspecial }
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvips>
%    \end{macrocode}
%
% \subsection{\texttt{pdfmode} and \texttt{(x)dvipdfmx}}
%
% Both \texttt{pdfmode} and \texttt{(x)dvipdfmx} directly produce PDF output
% and understand a shared set of specials for drawing commands.
%
%    \begin{macrocode}
%<*dvipdfmx|pdfmode|xdvipdfmx>
%    \end{macrocode}
%
% \subsubsection{Drawing}
%
% \begin{macro}{\@@_backend_literal:n, \@@_backend_literal:x}
%   Pass data through using a dedicated interface.
%    \begin{macrocode}
\cs_new_eq:NN \@@_backend_literal:n \__kernel_backend_literal_pdf:n
\cs_generate_variant:Nn \@@_backend_literal:n { x }
%    \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:x
      { \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:x
      { \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: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 \@@_backend_rectangle:nnnn #1#2#3#4
  {
     \@@_backend_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}{\@@_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:x
      { f \bool_if:NT \g_@@_draw_eor_bool * }
  }
\cs_new_protected:Npn \@@_backend_fillstroke:
  {
    \@@_backend_literal:x
      { B \bool_if:NT \g_@@_draw_eor_bool * }
  }
\cs_new_protected:Npn \@@_backend_clip:
  {
    \@@_backend_literal:x
      { 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:x
      {
        [
          \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:x
      { \dim_to_decimal_in_bp:n {#1} ~ w }
  }
\cs_new_protected:Npn \@@_backend_miterlimit:n #1
  { \@@_backend_literal:x { \fp_eval:n {#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_color_fill_cmyk:nnnn   ,
%     \@@_backend_color_stroke_cmyk:nnnn
%   }
% \begin{macro}
%   {
%     \@@_backend_color_fill_gray:n   ,
%     \@@_backend_color_stroke_gray:n
%   }
% \begin{macro}
%   {
%     \@@_backend_color_fill_rgb:nnn   ,
%     \@@_backend_color_stroke_rgb:nnn
%   }
% \begin{macro}{\@@_backend_color_select:n, \@@_backend_color_select:x}
% \begin{macro}{\@@_backend_color_reset:}
%    Color has to be split between \texttt{(x)dvipdfmx} and the PDF engines
%    as there is no color stack for fill/stroke separation in the former.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_color_fill_cmyk:nnnn #1#2#3#4
  {
    \@@_backend_color_select:x
      {
        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ 
        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
        k
      }
  }
\cs_new_protected:Npn \@@_backend_color_stroke_cmyk:nnnn #1#2#3#4
  {
    \@@_backend_color_select:x
      {
        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ 
        \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
        k
      }
  }
\cs_new_protected:Npn \@@_backend_color_fill_gray:n #1
  { \@@_backend_color_select:x { \fp_eval:n {#1} ~ g } }
\cs_new_protected:Npn \@@_backend_color_stroke_gray:n #1
  { \@@_backend_color_select:x { \fp_eval:n {#1} ~ G } }
\cs_new_protected:Npn \@@_backend_color_fill_rgb:nnn #1#2#3
  {
    \@@_backend_color_select:x
      { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ rg }
  }
\cs_new_protected:Npn \@@_backend_color_stroke_rgb:nnn #1#2#3
  {
    \@@_backend_color_select:x
      { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ RG }
  }
%<*pdfmode>
\cs_new_protected:Npx \@@_backend_color_select:n #1
  {
    \cs_if_exist:NTF \tex_pdfextension:D
      { \tex_pdfextension:D colorstack }
      { \tex_pdfcolorstack:D }
        \exp_not:N \l__kernel_color_stack_int push {#1}
      \group_insert_after:N \exp_not:N \@@_backend_color_reset:
  }
\cs_new_protected:Npx \@@_backend_color_reset:
  {
    \cs_if_exist:NTF \tex_pdfextension:D
      { \tex_pdfextension:D colorstack }
      { \tex_pdfcolorstack:D }
        \exp_not:N \l__kernel_color_stack_int pop \scan_stop:
  }
%</pdfmode>
%<*dvipdfmx|xdvipdfmx>
\cs_new_eq:NN \@@_backend_color_select:n \__kernel_backend_literal_pdf:n
%</dvipdfmx|xdvipdfmx>
\cs_generate_variant:Nn \@@_backend_color_select:n { x }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_cm:nnnn}
% \begin{macro}{\@@_backend_cm_aux:nnnn}
%   Another split here between \texttt{pdfmode} and \texttt{(x)dvipdfmx}.
%   In the former, we have a direct method to maintain alignment: the backend
%   can use a matrix itself. For \texttt{(x)dvipdfmx}, 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{(x)dvipdfmx}, but as a matched pair so not suitable for the
%   \enquote{stand alone} transformation set up here.)
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_cm:nnnn #1#2#3#4
  {
%<*pdfmode>
    \__kernel_backend_matrix:x
      {
        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
        \fp_eval:n {#3} ~ \fp_eval:n {#4}
      }
%</pdfmode>
%<*dvipdfmx|xdvipdfmx>
    \@@_backend_cm_decompose:nnnnN {#1} {#2} {#3} {#4}
      \@@_backend_cm_aux:nnnn
%</dvipdfmx|xdvipdfmx>
  }
%<*dvipdfmx|xdvipdfmx>
\cs_new_protected:Npn \@@_backend_cm_aux:nnnn #1#2#3#4
  {
    \__kernel_backend_literal:x
      {
        x:rotate~
        \fp_compare:nNnTF {#1} = \c_zero_fp
          { 0 }
          { \fp_eval:n { round ( -#1 , 5 ) } }
      }
    \__kernel_backend_literal:x
      {
        x:scale~
        \fp_eval:n { round ( #2 , 5 ) } ~
        \fp_eval:n { round ( #3 , 5 ) }
      }
    \__kernel_backend_literal:x
      {
        x:rotate~
        \fp_compare:nNnTF {#4} = \c_zero_fp
          { 0 }
          { \fp_eval:n { round ( -#4 , 5 ) } }
      }
  }
%</dvipdfmx|xdvipdfmx>
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_cm_decompose:nnnnN}
% \begin{macro}
%   {
%     \@@_backend_cm_decompose_auxi:nnnnN,
%     \@@_backend_cm_decompose_auxii:nnnnN,
%     \@@_backend_cm_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|xdvipdfmx>
\cs_new_protected:Npn \@@_backend_cm_decompose:nnnnN #1#2#3#4#5
  {
    \use:x
      {
        \@@_backend_cm_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_cm_decompose_auxi:nnnnN #1#2#3#4#5
  {
    \use:x
      {
        \@@_backend_cm_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_cm_decompose_auxii:nnnnN #1#2#3#4#5
  {
    \use:x
      {
        \@@_backend_cm_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_cm_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|xdvipdfmx>
%    \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:
%<*pdfmode>
    \@@_backend_cm:nnnn {#2} {#3} {#4} {#5}
%</pdfmode>
%<*dvipdfmx|xdvipdfmx>
    \__kernel_backend_literal:x
      {
        pdf:btrans~matrix~
        \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
        \fp_eval:n {#4} ~ \fp_eval:n {#5} ~
        0 ~ 0
      }
%</dvipdfmx|xdvipdfmx>
    \hbox_overlap_right:n { \box_use:N #1 }
%<*dvipdfmx|xdvipdfmx>
    \__kernel_backend_literal:n { pdf:etrans }
%</dvipdfmx|xdvipdfmx>
    \__kernel_backend_scope_end:
  }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvipdfmx|pdfmode|xdvipdfmx>
%    \end{macrocode}
%
% \subsection{\texttt{dvisvgm} backend}
%
%    \begin{macrocode}
%<*dvisvgm>
%    \end{macrocode}
%
% \begin{macro}{\@@_backend_literal:n, \@@_backend_literal:x}
%   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 { x }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_begin:, \@@_backend_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 \@@_backend_begin:
  {
    \@@_backend_scope_begin:
    \@@_backend_scope:n { transform="translate({?x},{?y})~scale(1,-1)" }
  }
\cs_new_protected:Npn \@@_backend_end:
  { \@@_backend_scope_end: }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_backend_scope_begin:, \@@_backend_scope_end:}
% \begin{macro}{\@@_backend_scope:n, \@@_backend_scope:x}
% \begin{variable}{\g_@@_draw_scope_int, \l_@@_draw_scope_int}
%   Several settings that with other backends 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 \@@_backend_scope_begin:
  {
    \int_set_eq:NN
      \l_@@_draw_scope_int
      \g_@@_draw_scope_int
    \group_begin:
      \int_gzero:N \g_@@_draw_scope_int
  }
\cs_new_protected:Npn \@@_backend_scope_end:
  {
      \prg_replicate:nn
        { \g_@@_draw_scope_int }
        { \@@_backend_literal:n { </g> } }
    \group_end:
    \int_gset_eq:NN
      \g_@@_draw_scope_int
      \l_@@_draw_scope_int
  }
\cs_new_protected:Npn \@@_backend_scope:n #1
  {
    \@@_backend_literal:n { <g~ #1 > }
    \int_gincr:N \g_@@_draw_scope_int
  }
\cs_generate_variant:Nn \@@_backend_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}{\@@_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_@@_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 adds spaces as required. Since paths should
%   be fully expanded there is no need to worry about the internal
%   \texttt{x}-type expansion.
%    \begin{macrocode}
\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: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}{\@@_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:
  { \@@_backend_scope:n { fill-rule="evenodd" } }
\cs_new_protected:Npn \@@_backend_nonzero_rule:
  { \@@_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_@@_clip_path_int
        \@@_backend_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
            />
          }
        \@@_backend_scope:x
          {
            clip-path =
              "url( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int)"
          }
      }
      {
        \@@_backend_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 \@@_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_@@_clip_path_int
        \@@_backend_literal:x
          {
            < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " >
              { ?nl }
            <path~d=" \g_@@_draw_path_tl "/> { ?nl }
            < /clipPath >
          }
        \@@_backend_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}{\@@_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:x
      {
        \@@_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
  {
    \@@_backend_scope:x
      {
        stroke-dasharray =
          "
            \tl_if_empty:oTF { \use_none:n #1 }
              { none }
              { \use_none:n #1 }
          " ~
          stroke-offset=" #2 "
      }
  }
\cs_new_protected:Npn \@@_backend_linewidth:n #1
  { \@@_backend_scope:x { stroke-width=" \dim_to_decimal:n {#1} " } }
\cs_new_protected:Npn \@@_backend_miterlimit:n #1
  { \@@_backend_scope:x { stroke-miterlimit=" \fp_eval:n {#1} " } }
\cs_new_protected:Npn \@@_backend_cap_butt:
  { \@@_backend_scope:n { stroke-linecap="butt" } }
\cs_new_protected:Npn \@@_backend_cap_round:
  { \@@_backend_scope:n { stroke-linecap="round" } }
\cs_new_protected:Npn \@@_backend_cap_rectangle:
  { \@@_backend_scope:n { stroke-linecap="square" } }
\cs_new_protected:Npn \@@_backend_join_miter:
  { \@@_backend_scope:n { stroke-linejoin="miter" } }
\cs_new_protected:Npn \@@_backend_join_round:
  { \@@_backend_scope:n { stroke-linejoin="round" } }
\cs_new_protected:Npn \@@_backend_join_bevel:
  { \@@_backend_scope:n { stroke-linejoin="bevel" } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_backend_color_fill_cmyk:nnnn   ,
%     \@@_backend_color_stroke_cmyk:nnnn
%   }
% \begin{macro}
%   {
%     \@@_backend_color_fill_gray:n   ,
%     \@@_backend_color_stroke_gray:n
%   }
% \begin{macro}
%   {
%     \@@_backend_color_fill_rgb:nnn   ,
%     \@@_backend_color_stroke_rgb:nnn
%   }
% \begin{macro}{\@@_backend_color_fill:nnn}
%  SVG fill color has to be covered outside of the stack, as for
%  \texttt{dvips}. Here, we are only allowed RGB colors so there is some
%  conversion to do.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_color_fill_cmyk:nnnn #1#2#3#4
  {
    \use:x
      {
        \@@_backend_color_fill:nnn
          { \fp_eval:n { -100 * ( (#1) * ( 1 - (#4) ) - 1 ) } }
          { \fp_eval:n { -100 * ( (#2) * ( 1 - (#4) ) + #4 - 1 ) } }
          { \fp_eval:n { -100 * ( (#3) * ( 1 - (#4) ) + #4 - 1 ) } }
      }
  }
\cs_new_protected:Npn \@@_backend_color_stroke_cmyk:nnnn #1#2#3#4
  {
    \@@_backend_select:x
      {
        cmyk~
        \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
        \fp_eval:n {#3} ~ \fp_eval:n {#4}
      }
  }
\cs_new_protected:Npn \@@_backend_color_fill_gray:n #1
  {
    \use:x
      {
        \@@_backend_color_gray_aux:n
          { \fp_eval:n { 100 * (#1) } }
      }
  }
\cs_new_protected:Npn \@@_backend_color_gray_aux:n #1
  { \@@_backend_color_fill:nnn {#1} {#1} {#1} }
\cs_new_protected:Npn \@@_backend_color_stroke_gray:n #1
  { \@@_backend_select:x { gray~ \fp_eval:n {#1} } }
\cs_new_protected:Npn \@@_backend_color_fill_rgb:nnn #1#2#3
  {
    \use:x
      {
        \@@_backend_color_fill:nnn
          { \fp_eval:n { 100 * (#1) } }
          { \fp_eval:n { 100 * (#2) } }
          { \fp_eval:n { 100 * (#3) } }
      }
  }
\cs_new_protected:Npn \@@_backend_color_fill:nnn #1#2#3
  {
    \@@_backend_scope:x
      {
        fill =
         "
           rgb
             (
               #1 \c_percent_str ,
               #2 \c_percent_str ,
               #3 \c_percent_str
             )
         "
      }
  }
\cs_new_protected:Npn \@@_backend_color_stroke_rgb:nnn #1#2#3
  {
    \@@_backend_select:x
      { rgb~ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_cm:nnnn}
%   The four arguments here are floats (the affine matrix), the last
%   two are a displacement vector. 
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_cm:nnnn #1#2#3#4
  {
    \@@_backend_scope:n
      {
       transform =
         "
           matrix
             (
               \fp_eval:n {#1} , \fp_eval:n {#2} ,
               \fp_eval:n {#3} , \fp_eval:n {#4} ,
               0pt , 0pt
             )
         "
      }
  }
%    \end{macrocode}
% \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#6#7
  {
    \__kernel_backend_scope_begin:
    \@@_backend_cm: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}
%</initex|package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
