summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3kernel/l3color.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3kernel/l3color.dtx')
-rw-r--r--macros/latex/contrib/l3kernel/l3color.dtx197
1 files changed, 110 insertions, 87 deletions
diff --git a/macros/latex/contrib/l3kernel/l3color.dtx b/macros/latex/contrib/l3kernel/l3color.dtx
index f77304a0a5..c6c8eb3262 100644
--- a/macros/latex/contrib/l3kernel/l3color.dtx
+++ b/macros/latex/contrib/l3kernel/l3color.dtx
@@ -2,7 +2,7 @@
%
%% File: l3color.dtx
%
-% Copyright (C) 2017-2021 The LaTeX Project
+% Copyright (C) 2017-2022 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
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2021-11-22}
+% \date{Released 2022-01-12}
%
% \maketitle
%
@@ -249,6 +249,9 @@
% General selection of color is safe when split across pages: a stack is
% used to ensure that the correct color is re-selected on the new page.
%
+% These commands set the current color (|.|): other more specialised functions
+% such as fill and stroke selectors do \emph{not} adjust this value.
+%
% \begin{function}{\color_select:n}
% \begin{syntax}
% \cs{color_select:n} \Arg{color expression}
@@ -281,9 +284,6 @@
% support this, and so color will need to be contained within a scope, such
% as \cs{draw_begin:}/\cs{draw_end:}.
%
-% Note that the \emph{current color} is the fill color, as this is used for
-% running text.
-%
% \begin{function}{\color_fill:n, \color_stroke:n}
% \begin{syntax}
% \cs{color_fill:n} \Arg{color expression}
@@ -538,12 +538,15 @@
% \begin{macro}{\@@_select:nn}
% Take an internal color specification and pass it to the driver. This code
% is needed to ensure the current color but will also be used by the
-% higher-level experimental material.
+% higher-level material.
% \begin{macrocode}
\cs_new_protected:Npn \@@_select:N #1
{ \exp_after:wN \@@_select:nn #1 }
\cs_new_protected:Npn \@@_select:nn #1#2
- { \use:c { @@_backend_select_ #1 :n } {#2} }
+ {
+ \use:c { @@_backend_select_ #1 :n } {#2}
+ \group_insert_after:N \@@_backend_reset:
+ }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -595,7 +598,7 @@
%
% \subsection{Utility functions}
%
-% \begin{macro}[int, TF, EXP]{\@@_if_defined:n}
+% \begin{macro}[TF, EXP]{\@@_if_defined:n}
% A simple wrapper to avoid needing to have the lookup repeated in too many
% places.
% \begin{macrocode}
@@ -632,33 +635,63 @@
%
% \begin{macro}{\@@_convert:nnN, \@@_convert:VVN}
% \begin{macro}{\@@_convert:nnnN, \@@_convert:nVnN, \@@_convert:nnVN}
-% \begin{macro}[aux, EXP]
+% \begin{macro}[EXP]
% {
+% \@@_convert_gray_gray:w
% \@@_convert_gray_rgb:w
% \@@_convert_gray_cmyk:w
% \@@_convert_cmyk_gray:w
% \@@_convert_cmyk_rgb:w
+% \@@_convert_cmyk_cmyk:w
% \@@_convert_rgb_gray:w
+% \@@_convert_rgb_rgb:w
% \@@_convert_rgb_cmyk:w
% }
-% \begin{macro}[aux, EXP]{\@@_convert_rgb_cmyk:nnnn}
-% Model conversion is carried out using standard formulae, as described in
-% the manual for \pkg{xcolor} (see also the \emph{PostScript Language
-% Reference Manual}).
+% \begin{macro}[EXP]{\@@_convert_rgb_cmyk:nnnn}
+% Model conversion is carried out using standard formulae for base models,
+% as described in the manual for \pkg{xcolor} (see also the \emph{PostScript
+% Language Reference Manual}). For other models direct conversion might not
+% be defined, so we go through the fallback models if necessary.
% \begin{macrocode}
\cs_new_protected:Npn \@@_convert:nnN #1#2#3
{ \@@_convert:nnVN {#1} {#2} #3 #3 }
\cs_generate_variant:Nn \@@_convert:nnN { VV }
+\cs_generate_variant:Nn \exp_last_unbraced:Nf { c }
\cs_new_protected:Npn \@@_convert:nnnN #1#2#3#4
{
\tl_set:Nx #4
{
- \cs_if_exist:cTF { @@_convert_ #1 _ #2 :w }
- { \use:c { @@_convert_ #1 _ #2 :w } #3 \s_@@_stop }
- { \use:c { c_@@_fallback_ #2 _tl } }
+ \cs_if_exist_use:cTF { @@_convert_ #1 _ #2 :w }
+ { #3 \s_@@_stop }
+ {
+ \cs_if_exist:cTF { @@_convert_ \use:c { c_@@_fallback_ #1 _tl } _ #2 :w }
+ {
+ \exp_last_unbraced:cf
+ { @@_convert_ \use:c { c_@@_fallback_ #1 _tl } _ #2 :w }
+ { \use:c { @@_convert_ #1 _ \use:c { c_@@_fallback_ #1 _tl } :w } #3 \s_@@_stop }
+ \s_@@_stop
+ }
+ {
+ \exp_last_unbraced:cf
+ { @@_convert_ \use:c { c_@@_fallback_ #2 _tl } _ #2 :w }
+ {
+ \cs_if_exist_use:cTF { @@_convert_ #1 _ \use:c { c_@@_fallback_ #2 _tl } :w }
+ { #3 \s_@@_stop }
+ {
+ \exp_last_unbraced:cf
+ { @@_convert_ \use:c { c_@@_fallback_ #1 _tl } _ \use:c { c_@@_fallback_ #2 _tl } :w }
+ { \use:c { @@_convert_ #1 _ \use:c { c_@@_fallback_ #1 _tl } :w } #3 \s_@@_stop }
+ \s_@@_stop
+ }
+ }
+ \s_@@_stop
+ }
+ }
}
}
\cs_generate_variant:Nn \@@_convert:nnnN { nV , nnV }
+\cs_new:Npn \@@_convert_gray_gray:w #1 \s_@@_stop
+ { #1 }
\cs_new:Npn \@@_convert_gray_rgb:w #1 \s_@@_stop
{ #1 ~ #1 ~ #1 }
\cs_new:Npn \@@_convert_gray_cmyk:w #1 \s_@@_stop
@@ -669,6 +702,8 @@
% \begin{macrocode}
\cs_new:Npn \@@_convert_rgb_gray:w #1 ~ #2 ~ #3 \s_@@_stop
{ \fp_eval:n { 0.3 * #1 + 0.59 * #2 + 0.11 * #3 } }
+\cs_new:Npn \@@_convert_rgb_rgb:w #1 \s_@@_stop
+ { #1 }
% \end{macrocode}
% The conversion from |rgb| to |cmyk| is the most complex: a two-step
% procedure which requires \emph{black generation} and \emph{undercolor
@@ -697,6 +732,8 @@
\fp_eval:n { 1 - min ( 1 , #2 + #4 ) } \c_space_tl
\fp_eval:n { 1 - min ( 1 , #3 + #4 ) }
}
+\cs_new:Npn \@@_convert_cmyk_cmyk:w #1 \s_@@_stop
+ { #1 }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -728,9 +765,9 @@
% \begin{macro}{\@@_parse_gray:n, \@@_parse_std:n}
% \begin{macro}{\@@_parse_break:w}
% \begin{macro}{\@@_parse_end:}
-% \begin{macro}[aux, EXP]{\@@_parse_mix:Nnnn, \@@_parse_mix:NVVn}
-% \begin{macro}[aux, EXP]{\@@_parse_mix:nNnn}
-% \begin{macro}[aux, EXP]
+% \begin{macro}[EXP]{\@@_parse_mix:Nnnn, \@@_parse_mix:NVVn}
+% \begin{macro}[EXP]{\@@_parse_mix:nNnn}
+% \begin{macro}[EXP]
% {
% \@@_parse_mix_gray:nw ,
% \@@_parse_mix_rgb:nw ,
@@ -1222,13 +1259,13 @@
% \end{macro}
% \end{macro}
%
-% \begin{macro}{\@@_select:}
+% \begin{macro}{\@@_finalise_current:}
% A backend-neutral location for \enquote{last minute} manipulations before
% handing off to the backend code. We set the special |.| syntax here: this
% will therefore always be available. The finalisation is separate from the
% main function so it can also be applied to \emph{e.g.}~page color.
% \begin{macrocode}
-\cs_new_protected:Npx \@@_select:
+\cs_new_protected:Npx \@@_finalise_current:
{
\tl_set:Nx \exp_not:c { l_@@_named_ . _tl }
{ \exp_not:N \@@_model:N \exp_not:N \l_@@_current_tl }
@@ -1236,7 +1273,6 @@
\prop_put:NVx \exp_not:c { l_@@_named_ . _prop }
\exp_not:c { l_@@_named_ . _tl }
{ \exp_not:N \@@_values:N \exp_not:N \l_@@_current_tl }
- \@@_select:N \exp_not:N \l_@@_current_tl
}
% \end{macrocode}
% \end{macro}
@@ -1254,13 +1290,15 @@
\cs_new_protected:Npn \color_select:n #1
{
\@@_parse:nN {#1} \l_@@_current_tl
- \@@_select:
+ \@@_finalise_current:
+ \@@_select:N \l_@@_current_tl
}
\cs_new_protected:Npn \color_select:nn #1#2
{
\@@_select_main:Nw \l_@@_current_tl
#1 / / \s_@@_mark #2 / / \s_@@_stop
- \@@_select:
+ \@@_finalise_current:
+ \@@_select:N \l_@@_current_tl
}
% \end{macrocode}
% If the first color model is the fixed one, or if there is no fixed
@@ -1692,12 +1730,12 @@
%
% \begin{variable}
% {\c_@@_fallback_cmyk_tl, \c_@@_fallback_gray_tl, \c_@@_fallback_rgb_tl}
-% Conversion from Separation or DeviceN spaces may not be possible; have
-% a fallback to black.
+% For every colorspace, we define one of the base colorspaces as a fallback.
+% The base colorspaces themselves are their own fallback.
% \begin{macrocode}
-\tl_const:Nn \c_@@_fallback_cmyk_tl { 0 ~ 0 ~ 0 ~ 1 }
-\tl_const:Nn \c_@@_fallback_gray_tl { 1 }
-\tl_const:Nn \c_@@_fallback_rgb_tl { 1 ~ 1 ~ 1 }
+\tl_const:Nn \c_@@_fallback_cmyk_tl { cmyk }
+\tl_const:Nn \c_@@_fallback_gray_tl { gray }
+\tl_const:Nn \c_@@_fallback_rgb_tl { rgb }
% \end{macrocode}
% \end{variable}
%
@@ -1803,14 +1841,13 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_model_init:nn}
+% \begin{macro}{\@@_model_init:nnnn, \@@_model_init:nnnx}
% A shared auxiliary to do the basics of setting up a new model: reserve a
-% number, create a fallback and white-equivalent, set up links to the backend.
+% number, create a white-equivalent, set up links to the backend.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_model_init:nnnnn #1#2#3#4#5
+\cs_new_protected:Npn \@@_model_init:nnnn #1#2#3#4
{
\int_gincr:N \g_@@_model_int
- \tl_const:cn { c_@@_fallback_ #1 _tl } { #4 }
\clist_map_inline:nn { fill , stroke , select }
{
\cs_new_protected:cpx { @@_backend_ ##1 _ #1 :n } ####1
@@ -1822,23 +1859,13 @@
\cs_new_protected:cpx { @@_model_ #1 _white: }
{
\prop_put:Nnn \exp_not:N \l_@@_named_white_prop {#1}
- { \exp_not:n {#5} }
+ { \exp_not:n {#4} }
\exp_not:N \int_compare:nNnF { \tex_currentgrouplevel:D } = 0
{ \group_insert_after:N \exp_not:c { @@_model_ #1 _ white: } }
}
\use:c { @@_model_ #1 _white: }
}
-\cs_generate_variant:Nn \@@_model_init:nnnnn { nnnxx }
-\cs_new_protected:Npn \@@_model_init:nnn #1#2#3
- {
- \@@_model_init:nnnxx { #1 } { #2 } { #3 }
- {
- 1 \prg_replicate:nn { #2 - 1 } { ~ 1 }
- }
- {
- 0 \prg_replicate:nn { #2 - 1 } { ~ 0 }
- }
- }
+\cs_generate_variant:Nn \@@_model_init:nnnn { nnnx }
% \end{macrocode}
% \end{macro}
%
@@ -1921,7 +1948,7 @@
\cs_new_protected:Npn \@@_model_separation:w
#1 , #2 , #3 , #4 , #5 \s_@@_stop #6#7#8
{
- \@@_model_init:nnn {#6} { 1 } { separation }
+ \@@_model_init:nnnn {#6} { 1 } { separation } { 0 }
\cs_new_eq:cN { @@_parse_mix_ #6 :nw } \@@_parse_mix_gray:nw
\cs_new:cpn { @@_parse_model_ #6 :w } ##1 , ##2 \s_@@_stop
{ {#6} { \@@_parse_number:n {##1} } }
@@ -1933,6 +1960,7 @@
}
\cs_new_protected:Npn \@@_model_separation_cmyk:nnnnnn #1#2#3#4#5#6
{
+ \tl_const:cn { c_@@_fallback_ #1 _tl } { cmyk }
\cs_new:cpn { @@_convert_ #1 _cmyk:w } ##1 \s_@@_stop
{
\fp_eval:n {##1 * #3} ~
@@ -1940,43 +1968,31 @@
\fp_eval:n {##1 * #5} ~
\fp_eval:n {##1 * #6}
}
- \@@_model_convert:nnn {#1} { cmyk } { rgb }
- \@@_model_convert:nnn {#1} { cmyk } { gray }
+ \cs_new:cpn { @@_convert_cmyk_ #1 :w } ##1 \s_@@_stop { 1 }
\prop_gput:Nnn \g_@@_alternative_values_prop {#1} { #3 , #4 , #5 , #6 }
\@@_backend_separation_init:nnnnn {#2} { /DeviceCMYK } { }
{ 0 ~ 0 ~ 0 ~ 0 } { #3 ~ #4 ~ #5 ~ #6 }
}
\cs_new_protected:Npn \@@_model_separation_rgb:nnnnnn #1#2#3#4#5#6
{
+ \tl_const:cn { c_@@_fallback_ #1 _tl } { rgb }
\cs_new:cpn { @@_convert_ #1 _rgb:w } ##1 \s_@@_stop
{
\fp_eval:n {##1 * #3} ~
\fp_eval:n {##1 * #4} ~
\fp_eval:n {##1 * #5}
}
- \@@_model_convert:nnn {#1} { rgb } { cmyk }
- \@@_model_convert:nnn {#1} { rgb } { gray }
+ \cs_new:cpn { @@_convert_rgb_ #1 :w } ##1 \s_@@_stop { 1 }
\prop_gput:Nnn \g_@@_alternative_values_prop {#1} { #3 , #4 , #5 }
\@@_backend_separation_init:nnnnn {#2} { /DeviceRGB } { }
{ 0 ~ 0 ~ 0 } { #3 ~ #4 ~ #5 }
}
\cs_new_protected:Npn \@@_model_separation_gray:nnnnnn #1#2#3#4#5#6
{
- \cs_new:cpn { @@_convert_ #1 _cmyk:w } ##1 \s_@@_stop
- {
- \fp_eval:n {##1 * #3} ~
- \fp_eval:n {##1 * #3} ~
- \fp_eval:n {##1 * #3} ~
- \fp_eval:n {##1 * #3}
- }
+ \tl_const:cn { c_@@_fallback_ #1 _tl } { gray }
\cs_new:cpn { @@_convert_ #1 _gray:w } ##1 \s_@@_stop
{ \fp_eval:n {##1 * #3} }
- \cs_new:cpn { @@_convert_ #1 _rgb:w } ##1 \s_@@_stop
- {
- \fp_eval:n {##1 * #3} ~
- \fp_eval:n {##1 * #3} ~
- \fp_eval:n {##1 * #3}
- }
+ \cs_new:cpn { @@_convert_gray_ #1 :w } ##1 \s_@@_stop { 1 }
\prop_gput:Nnn \g_@@_alternative_values_prop {#1} {#3}
\@@_backend_separation_init:nnnnn {#2} { /DeviceGray } { } { 0 } {#3}
}
@@ -2013,19 +2029,18 @@
% If a CIELAB space is being set up, we need the illuminant, then create
% the appropriate set up. At present, this doesn't include \texttt{BlackPoint}
% or \texttt{Range} data, but that may be added later. As CIELAB colors
-% cannot be converted to anything else, we fallback to producing black: the
-% user should set up a second model for colors set up this way.
+% cannot be converted to anything else, we fallback to producing black in the
+% gray colorspace: the user should set up a second model for colors set up this way.
% \begin{macrocode}
\cs_new_protected:Npn \@@_model_separation_CIELAB:nnnnnnn #1#2#3#4#5#6#7
{
\tl_if_exist:cTF { c_@@_model_whitepoint_CIELAB_ #1 _tl }
{
\@@_backend_separation_init_CIELAB:nnn {#1} {#3} { #4 ~ #5 ~ #6 }
- \cs_new:cpn { @@_convert_ #2 _cmyk:w } ##1 \s_@@_stop
- { 0 ~ 0 ~ 0 ~ 1 }
- \cs_new:cpn { @@_convert_ #2 _rgb:w } ##1 \s_@@_stop
- { 1 ~ 1 ~ 1 }
+ \tl_const:cn { c_@@_fallback_ #2 _tl } { gray }
\cs_new:cpn { @@_convert_ #2 _gray:w } ##1 \s_@@_stop
+ { 0 }
+ \cs_new:cpn { @@_convert_gray_ #2 :w } ##1 \s_@@_stop
{ 1 }
}
{
@@ -2162,12 +2177,18 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_model_devicen:nnnn #1#2#3#4
{
- \@@_model_init:nnn {#4} {#1} { devicen }
+ \@@_model_init:nnnx {#4} {#1} { devicen }
+ {
+ 0 \prg_replicate:nn { #1 - 1 } { ~ 0 }
+ }
\cs_if_exist_use:cF { @@_model_devicen_parse_ #1 :nn }
{ \@@_model_devicen_parse_generic:nn }
{#4} {#1}
\@@_model_devicen_init:nnn {#1} {#2} {#3}
- \@@_model_devicen_convert:nnn {#4} {#2} {#3}
+ \@@_model_devicen_convert:nnnx {#4} {#2} {#3}
+ {
+ 1 \prg_replicate:nn { #1 - 1 } { ~ 1 }
+ }
}
% \end{macrocode}
% For short lists of DeviceN colors, we can use hand-tuned parsing. This
@@ -2382,30 +2403,29 @@
% to other parameter-based spaces. Essentially the approach is exactly the same
% as the PostScript, just expressed in \TeX{} terms.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_model_devicen_convert:nnn #1#2#3
+\cs_new_protected:Npn \@@_model_devicen_convert:nnnn #1#2#3
{
- \use:c { @@_model_devicen_convert_ #2 :nn } {#1} {#3}
+ \use:c { @@_model_devicen_convert_ #2 :nnn } {#1} {#3}
}
-\cs_new_protected:Npn \@@_model_devicen_convert_cmyk:nn #1#2
+\cs_generate_variant:Nn \@@_model_devicen_convert:nnnn { nnnx }
+\cs_new_protected:Npn \@@_model_devicen_convert_cmyk:nnn #1#2
{
- \@@_model_convert:nnn {#1} { cmyk } { gray }
- \@@_model_convert:nnn {#1} { cmyk } { rgb }
- \@@_model_devicen_convert:nnnn {#1} { cmyk } { 4 } {#2}
+ \tl_const:cn { c_@@_fallback_ #1 _tl } { cmyk }
+ \@@_model_devicen_convert:nnnnn {#1} { cmyk } { 4 } {#2}
}
-\cs_new_protected:Npn \@@_model_devicen_convert_gray:nn #1#2
+\cs_new_protected:Npn \@@_model_devicen_convert_gray:nnn #1#2
{
- \@@_model_convert:nnn {#1} { gray } { cmyk }
- \@@_model_convert:nnn {#1} { gray } { rgb }
- \@@_model_devicen_convert:nnnn {#1} { gray } { 1 } {#2}
+ \tl_const:cn { c_@@_fallback_ #1 _tl } { gray }
+ \@@_model_devicen_convert:nnnnn {#1} { gray } { 1 } {#2}
}
-\cs_new_protected:Npn \@@_model_devicen_convert_rgb:nn #1#2
+\cs_new_protected:Npn \@@_model_devicen_convert_rgb:nnn #1#2
{
- \@@_model_convert:nnn {#1} { rgb } { cmyk }
- \@@_model_convert:nnn {#1} { rgb } { gray }
- \@@_model_devicen_convert:nnnn {#1} { rgb } { 3 } {#2}
+ \tl_const:cn { c_@@_fallback_ #1 _tl } { rgb }
+ \@@_model_devicen_convert:nnnnn {#1} { rgb } { 3 } {#2}
}
-\cs_new_protected:Npn \@@_model_devicen_convert:nnnn #1#2#3#4
+\cs_new_protected:Npn \@@_model_devicen_convert:nnnnn #1#2#3#4#5
{
+ \cs_new:cpn { @@_convert_ #2 _ #1 :w } ##1 \s_@@_stop {#5}
\cs_new:cpx { @@_convert_ #1 _ #2 :w } ##1 \s_@@_stop
{
\exp_not:c { @@_convert_devicen_ #2 : \prg_replicate:nn {#3} { n } w }
@@ -2607,7 +2627,10 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_model_iccbased_aux:nnnnnn #1#2#3#4#5#6
{
- \@@_model_init:nnnnn {#5} {#1} { iccbased } {#2} {#3}
+ \@@_model_init:nnnn {#5} {#1} { iccbased } {#3}
+ \tl_const:cn { c_@@_fallback_ #5 _tl } { gray }
+ \cs_new:cpn { @@_convert_ #5 _gray:w } ##1 \s_@@_stop { 0 }
+ \cs_new:cpn { @@_convert_gray_ #5 :w } ##1 \s_@@_stop { #2 }
\use:c { @@_model_devicen_parse_ #1 :nn } {#5} {#1}
\exp_args:Nx \@@_backend_iccbased_init:nnn
{ \file_full_name:n {#6} } {#1} {#4}