% \iffalse meta-comment
%
%% File: l3backend-color.dtx
%
% Copyright (C) 2019,2020 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-color} package\\ Backend color 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 2020-08-07}
%
% \maketitle
%
% \begin{documentation}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3backend-color} Implementation}
%
%    \begin{macrocode}
%<*package>
%<@@=color>
%    \end{macrocode}
%
% Color support is split into two parts: a \enquote{general} concept and
% one directly linked to drawings (or rather the split between filling
% and stroking). General color is relatively easy to handle: we have a color
% stack available with all modern drivers, and can use that.
% Whilst \texttt{(x)dvipdfmx} does have its own approach to color specials,
% it is easier to use \texttt{dvips}-like ones for all cases except direct
% PDF output.
%
% \subsection{\texttt{dvips}-style}
%
%    \begin{macrocode}
%<*dvisvgm|dvipdfmx|dvips|xdvipdfmx>
%    \end{macrocode}
%
% \begin{macro}{\@@_backend_pickup:N}
% \begin{macro}{\@@_backend_pickup:w}
%   Allow for \LaTeXe{} color. Here, the possible input values are limited:
%   \texttt{dvips}-style colors can mainly be taken as-is with the exception
%   spot ones (here we need a model and a tint). The \texttt{x}-type expansion
%   is there to cover the case where \pkg{xcolor} is in use.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_pickup:N #1 { }
\cs_if_exist:cT { ver@color.sty }
  {
     \cs_set_protected:Npn \@@_backend_pickup:N #1
      {
        \exp_args:NV \tl_if_head_is_space:nTF \current@color
          {
            \tl_set:Nx #1
               {
                 { \exp_after:wN \use:n \current@color }
                 { 1 }
               }
          }
          {
            \exp_last_unbraced:Nx \@@_backend_pickup:w
              { \current@color } \s_@@_stop #1
          }
      }
    \cs_new_protected:Npn \@@_backend_pickup:w #1 ~ #2 \s_@@_stop #3
      { \tl_set:Nn #3 { {#1} {#2} } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_backend_select_cmyk:n  ,
%     \@@_backend_select_gray:n  ,
%     \@@_backend_select_rgb:n   ,
%     \@@_backend_select:n
%   }
% \begin{macro}{\@@_backend_reset:}
% \begin{macro}{color.sc, color.fc}
%    Push the data to the stack. In the case of \texttt{dvips} also saves the
%    drawing color in raw PostScript.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_select_cmyk:n #1
  { \@@_backend_select:n { cmyk ~ #1 } }
\cs_new_protected:Npn \@@_backend_select_gray:n #1
  { \@@_backend_select:n { gray ~ #1 } }
\cs_new_protected:Npn \@@_backend_select_rgb:n #1
  { \@@_backend_select:n { rgb ~ #1 } }
\cs_new_protected:Npn \@@_backend_select:n #1
  {
    \__kernel_backend_literal:n { color~push~ #1 }
%<*dvips>
    \__kernel_backend_postscript:n { /color.sc~ { ~ } ~def }
    \__kernel_backend_postscript:n { /color.fc~ { ~ } ~def }
%</dvips>
    \group_insert_after:N \@@_backend_reset:
  }
\cs_new_protected:Npn \@@_backend_reset:
  { \__kernel_backend_literal:n { color~pop } }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_select_separation:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_select_separation:nn #1#2
  { \@@_backend_select:n {#1} }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvisvgm|dvipdfmx|dvips|xdvipdfmx>
%    \end{macrocode}
%
% \subsection{\texttt{pdfmode}}
%
%    \begin{macrocode}
%<*pdfmode>
%    \end{macrocode}
%
% \begin{macro}{\@@_backend_pickup:N}
% \begin{macro}{\@@_backend_pickup:w}
%   The current color in driver-dependent format: pick up the package-mode
%   data if available. We end up converting back and forward in this route as
%   we store our color data in \texttt{dvips} format.
%   The \tn{current@color} needs to be \texttt{x}-expanded before
%   \cs{@@_backend_pickup:w} breaks it apart, because for instance
%   \pkg{xcolor} sets it to be instructions to generate a color
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_pickup:N #1 { }
\cs_if_exist:cT { ver@color.sty }
  {
    \cs_set_protected:Npn \@@_backend_pickup:N #1
      {
        \exp_last_unbraced:Nx \@@_backend_pickup:w
          { \current@color } ~ 0 ~ 0 ~ 0 \s_@@_stop #1
      }
    \cs_new_protected:Npn \@@_backend_pickup:w
      #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 \s_@@_stop #7
      {
        \str_if_eq:nnTF {#2} { g }
          { \tl_set:Nn #7 { { gray } {#1} } }
          {
            \str_if_eq:nnTF {#4} { rg }
              { \tl_set:Nn #7 { { rgb } { #1 ~ #2 ~ #3 } } }
              {
                 \str_if_eq:nnTF {#5} { k }
                   { \tl_set:Nn #7 { { cmyk } { #1 ~ #2 ~ #3 ~ #4 } } }
                   {
                     \str_if_eq:nnTF {#2} { cs }
                       {
                         \tl_set:Nx #7 { { \use:n #1 } { #5 } }
                       }
                       {
                         \tl_set:Nn #7 { { gray } { 0 } }
                       }
                   }
              }
          }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{variable}{\l__kernel_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__kernel_color_stack_int
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}
%   {
%     \@@_backend_select_cmyk:n ,
%     \@@_backend_select_gray:n ,
%     \@@_backend_select_rgb:n
%   }
% \begin{macro}{\@@_backend_reset:}
%   Simply dump the data, but allowing for \LuaTeX{}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_select_cmyk:n #1
  { \@@_backend_select:n { #1 ~ k ~ #1 ~ K } }
\cs_new_protected:Npn \@@_backend_select_gray:n #1
  { \@@_backend_select:n { #1 ~ g ~ #1 ~ G } }
\cs_new_protected:Npn \@@_backend_select_rgb:n #1
  { \@@_backend_select:n { #1 ~ rg ~ #1 ~ RG } }
\cs_new_protected:Npx \@@_backend_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_reset:
  }
\cs_new_protected:Npx \@@_backend_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:
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_backend_select_separation:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_select_separation:nn #1#2
  { \@@_backend_select:n { /#1 ~ cs ~ /#1 ~ CS ~ #2 ~ scn ~ #2 ~ SCN } }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</pdfmode>
%    \end{macrocode}
%
% \subsection{Fill and stroke color}
%
% Here, \texttt{(x)dvipdfmx} follows \texttt{pdfmode}, while for \texttt{dvips}
% we have to manage fill and stroke color ourselves. We also handle
% \texttt{dvisvgm} independently, as there we can create SVG directly.
%
%    \begin{macrocode}
%<*dvipdfmx|pdfmode|xdvipdfmx>
%    \end{macrocode}
%
% \begin{macro}
%   {
%     \@@_backend_fill_cmyk:n   ,
%     \@@_backend_fill_gray:n   ,
%     \@@_backend_fill_rgb:n    ,
%     \@@_backend_stroke_cmyk:n ,
%     \@@_backend_stroke_gray:n ,
%     \@@_backend_stroke_rgb:n
%   }
%   Drawing (fill/stroke) color is handled in \texttt{(x)dvipdfmx} in the
%   same way as \texttt{pdfmode}. We use the same approach as earlier, except the
%   color stack is not involved so the generic direct PDF operation is used.
%   There is no worry about the nature of strokes: everything is handled
%   automatically.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_fill_cmyk:n #1
  { \__kernel_backend_literal_pdf:n { #1 ~ k } }
\cs_new_protected:Npn \@@_backend_fill_gray:n #1
  { \__kernel_backend_literal_pdf:n { #1 ~ g } }
\cs_new_protected:Npn \@@_backend_fill_rgb:n #1
  { \__kernel_backend_literal_pdf:n { #1 ~ rg } }
  \cs_new_protected:Npn \@@_backend_stroke_cmyk:n #1
  { \__kernel_backend_literal_pdf:n { #1 ~ K } }
\cs_new_protected:Npn \@@_backend_stroke_gray:n #1
  { \__kernel_backend_literal_pdf:n { #1 ~ G } }
\cs_new_protected:Npn \@@_backend_stroke_rgb:n #1
  { \__kernel_backend_literal_pdf:n { #1 ~ RG } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_backend_fill_separation:nn,
%     \@@_backend_stroke_separation:nn
%   }
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_fill_separation:nn #1#2
  { \__kernel_backend_literal_pdf:n { /#1 ~ cs ~ #2 ~ scn } }
\cs_new_protected:Npn \@@_backend_stroke_separation:nn #1#2
  { \__kernel_backend_literal_pdf:n { /#1 ~ CS ~ #2 ~ SCN } }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvipdfmx|pdfmode|xdvipdfmx>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*dvips>
%    \end{macrocode}
%
% \begin{macro}
%   {
%     \@@_backend_fill_cmyk:n   ,
%     \@@_backend_fill_gray:n   ,
%     \@@_backend_fill_rgb:n    ,
%     \@@_backend_stroke_cmyk:n ,
%     \@@_backend_stroke_gray:n ,
%     \@@_backend_stroke_rgb:n
%   }
%   All questions of saving the non-stacked data.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_fill_cmyk:n #1
  { \__kernel_backend_postscript:n { /color.fc { #1 ~ setcmykcolor } def } }
\cs_new_protected:Npn \@@_backend_fill_gray:n #1
  { \__kernel_backend_postscript:n { /color.fc { #1 ~ setgray } def } }
\cs_new_protected:Npn \@@_backend_fill_rgb:n #1
  { \__kernel_backend_postscript:n { /color.fc { #1 ~ setrgbcolor } def } }
  \cs_new_protected:Npn \@@_backend_stroke_cmyk:n #1
  { \__kernel_backend_postscript:n { /color.sc { #1 ~ setcmykcolor } def } }
\cs_new_protected:Npn \@@_backend_stroke_gray:n #1
  { \__kernel_backend_postscript:n { /color.sc { #1 ~ setgray } def } }
\cs_new_protected:Npn \@@_backend_stroke_rgb:n #1
  { \__kernel_backend_postscript:n { /color.sc { #1 ~ setrgbcolor } def } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_backend_fill_separation:nn,
%     \@@_backend_stroke_separation:nn
%   }
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_fill_separation:nn #1#2
  { \__kernel_backend_postscript:n { /color.fc { #1 } def } }
\cs_new_protected:Npn \@@_backend_stroke_separation:nn #1#2
  { \__kernel_backend_postscript:n { /color.sc { #1 } def } }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvips>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*dvisvgm>
%    \end{macrocode}
%
% \begin{macro}
%   {
%     \@@_backend_fill_cmyk:n   ,
%     \@@_backend_stroke_cmyk:n
%   }
% \begin{macro}{\@@_backend_cmyk:nw}
% \begin{macro}
%   {
%     \@@_backend_fill_gray:n   ,
%     \@@_backend_stroke_gray:n
%   }
% \begin{macro}{\@@_backend_gray:nn, \@@_backend_gray_aux:n}
% \begin{macro}
%   {
%     \@@_backend_fill_rgb:n   ,
%     \@@_backend_stroke_rgb:n
%   }
% \begin{macro}{\@@_backend_rgb:nw}
% \begin{macro}{\@@_backend:nnnn}
%   For drawings in SVG, we use scopes for all colors. That
%   requires using \texttt{RGB} values, which luckily are easy to
%   convert here (|cmyk| to |RGB| is a fixed function).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_fill_cmyk:n #1
  { \@@_backend_cmyk:nw { fill } #1 \s_@@_stop }
\cs_new_protected:Npn \@@_backend_stroke_cmyk:n #1
  { \@@_backend_cmyk:nw { stroke } #1 \s_@@_stop }
\cs_new_protected:Npn \@@_backend_cmyk:nw
  #1#2 ~ #3 ~ #4 ~ #5 \s_@@_stop
  {
    \use:x
      {
        \@@_backend:nnnn
          {#1}
          { \fp_eval:n { -100 * ( 1 - min ( 1 , #2 + #5 ) ) } }
          { \fp_eval:n { -100 * ( 1 - min ( 1 , #3 + #5 ) ) } }
          { \fp_eval:n { -100 * ( 1 - min ( 1 , #4 + #5 ) ) } }
      }
  }
\cs_new_protected:Npn \@@_backend_fill_gray:n #1
  { \@@_backend_grab:nn { fill } {#1} }
\cs_new_protected:Npn \@@_backend_stroke_gray:n #1
  { \@@_backend_grab:nn { stroke } {#1} }
\cs_new_protected:Npn \@@_backend_gray:nn #1#2
  {
    \use:x
      {
        \@@_backend_gray_aux:nn
          {#1}
          { \fp_eval:n { 100 * (#2) } }
      }
  }
\cs_new_protected:Npn \@@_backend_gray_aux:nn #1#2
  { \@@_backend:nnn {#1} {#2} {#2} {#2} }
\cs_new_protected:Npn \@@_backend_fill_rgb:n #1
  { \@@_backend_rgb:nw { fill } #1 \s_@@_stop }
\cs_new_protected:Npn \@@_backend_stroke_rgb:n #1
  { \@@_backend_rgb:nw { stroke } #1 \s_@@_stop }
\cs_new_protected:Npn \@@_backend_rgb:nw
  #1#2 ~ #3 ~ #4\s_@@_stop
  {
    \use:x
      {
        \@@_backend:nnnn
          { fill }
          { \fp_eval:n { 100 * (#2) } }
          { \fp_eval:n { 100 * (#3) } }
          { \fp_eval:n { 100 * (#4) } }
      }
  }
\cs_new_protected:Npx \@@_backend:nnnn #1#2#3#4
  {
    \__kernel_backend_scope:n
      {
        #1 =
         "
           rgb
             (
               #2 \c_percent_str ,
               #3 \c_percent_str ,
               #4 \c_percent_str
             )
         "
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \@@_backend_fill_separation:nn,
%     \@@_backend_stroke_separation:nn
%   }
%   At present, these are no-ops.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_backend_fill_separation:nn #1#2
  { }
\cs_new_protected:Npn \@@_backend_stroke_separation:nn #1#2
  { }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</dvisvgm>
%    \end{macrocode}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
