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.dtx142
1 files changed, 122 insertions, 20 deletions
diff --git a/macros/latex/contrib/l3kernel/l3color.dtx b/macros/latex/contrib/l3kernel/l3color.dtx
index 8fc7268cdb..33b28721ed 100644
--- a/macros/latex/contrib/l3kernel/l3color.dtx
+++ b/macros/latex/contrib/l3kernel/l3color.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-08-05}
+% \date{Released 2022-08-23}
%
% \maketitle
%
@@ -95,6 +95,7 @@
% \item \texttt{cmyk} Cyan-magenta-yellow-black color, with four axes, one for
% each of the components
% \end{itemize}
+%
% There are also interface models: these are convenient for users but have
% to be manipulated before storing/passing to the backend. Interface models
% are primarily integer-based: see below for more detail. The supported
@@ -118,6 +119,20 @@
% \end{itemize}
% All interface models are internally stored as |rgb|.
%
+% Finally, there are a small number of models which are parsed to allow
+% data transfer from \pkg{xcolor} but which should not be used by end-users.
+% These are
+% \begin{itemize}
+% \item \texttt{cmy} Cyan-magenta-yellow color with three axes, one for
+% each of the components; converted to |cmyk|
+% \item \texttt{tHsb} \enquote{Tuned} hue-saturation-brightness color with three
+% axes, integer in the range $[0,360]$ for hue, real values in the range
+% $[0,1]$ for saturation and brightness; converted to |rgb| using the
+% standard tuning map defined by \pkg{xcolor}
+% \item \texttt{\&spot} Spot color tint with one value; treated as a gray
+% tint as spot color data is not available for extraction
+% \end{itemize}
+%
% To allow parsing of data from \pkg{xcolor}, any leading model up the first
% \texttt{:} will be discarded; the approach of selecting an internal form
% for data is \emph{not} used in \pkg{l3color}.
@@ -235,6 +250,15 @@
% it to be saved to a name.
% \end{function}
%
+% \begin{function}[EXP, pTF, added = 2022-08-12]{\color_if_exist:n}
+% \begin{syntax}
+% \cs{color_if_exist:n} \Arg{name}
+% \cs{color_if_exist:n} \Arg{name} \Arg{true code} \Arg{false code}
+% \end{syntax}
+% Tests whether \meta{name} is currently defined to provide a color
+% specification.
+% \end{function}
+%
% \begin{function}[added = 2021-05-11]{\color_show:n, \color_log:n}
% \begin{syntax}
% \cs{color_show:n} \Arg{name}
@@ -545,10 +569,7 @@
% current color \enquote{now}.
% \begin{macrocode}
\cs_new_protected:Npn \color_ensure_current:
- {
- \@@_backend_pickup:N \l_@@_current_tl
- \@@_select:N \l_@@_current_tl
- }
+ { \@@_select:N \l_@@_current_tl }
% \end{macrocode}
% \end{macro}
%
@@ -625,12 +646,12 @@
%
% \subsection{Utility functions}
%
-% \begin{macro}[TF, EXP]{\@@_if_defined:n}
+% \begin{macro}[pTF, EXP]{\color_if_exist:n}
% A simple wrapper to avoid needing to have the lookup repeated in too many
% places.To guard against a color created in a group, we need to test for
% entries in the |prop|.
% \begin{macrocode}
-\prg_new_conditional:Npnn \@@_if_defined:n #1 { T, F, TF }
+\prg_new_conditional:Npnn \color_if_exist:n #1 { p , T, F, TF }
{
\prop_if_exist:cTF { l_@@_named_ #1 _prop }
{
@@ -679,6 +700,7 @@
% \@@_convert_rgb_rgb:w
% \@@_convert_rgb_cmyk:w
% }
+% \begin{macro}[EXP]{\@@_convert_rgb_cmyk:nnn}
% \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
@@ -742,18 +764,28 @@
% removal} functions. The PostScript reference describes them as
% device-dependent, but following \pkg{xcolor} we assume they are linear.
% Moreover, as the likelihood of anyone using a non-unitary matrix here is
-% tiny, we simplify and treat those two concepts as no-ops.
+% tiny, we simplify and treat those two concepts as no-ops. To allow code
+% sharing with parsing of |cmy| values, we have an intermediate function
+% here (\cs{@@_convert_rgb_cmyk:nnn}) which actually takes |cmy| values
+% as input.
% \begin{macrocode}
\cs_new:Npn \@@_convert_rgb_cmyk:w #1 ~ #2 ~ #3 \s_@@_stop
{
- \exp_args:Nf \@@_convert_rgb_cmyk:nnnn
- { \fp_eval:n { min ( 1 - #1 , 1 - #2 , 1 - #3 ) } } {#1} {#2} {#3}
+ \exp_args:Neee \@@_convert_rgb_cmyk:nnn
+ { \fp_eval:n { 1 - #1 } }
+ { \fp_eval:n { 1 - #2 } }
+ { \fp_eval:n { 1 - #3 } }
+ }
+\cs_new:Npn \@@_convert_rgb_cmyk:nnn #1#2#3
+ {
+ \exp_args:Ne \@@_convert_rgb_cmyk:nnnn
+ { \fp_eval:n { min( #1, #2 , #3 ) } } {#1} {#2} {#3}
}
\cs_new:Npn \@@_convert_rgb_cmyk:nnnn #1#2#3#4
{
- \fp_eval:n { min ( 1 , max ( 0 , 1 - #2 - #1 ) ) } \c_space_tl
- \fp_eval:n { min ( 1 , max ( 0 , 1 - #3 - #1 ) ) } \c_space_tl
- \fp_eval:n { min ( 1 , max ( 0 , 1 - #4 - #1 ) ) } \c_space_tl
+ \fp_eval:n { min ( 1 , max ( 0 , #2 - #1 ) ) } \c_space_tl
+ \fp_eval:n { min ( 1 , max ( 0 , #3 - #1 ) ) } \c_space_tl
+ \fp_eval:n { min ( 1 , max ( 0 , #4 - #1 ) ) } \c_space_tl
#1
}
\cs_new:Npn \@@_convert_cmyk_gray:w #1 ~ #2 ~ #3 ~ #4 \s_@@_stop
@@ -771,6 +803,7 @@
% \end{macro}
% \end{macro}
% \end{macro}
+% \end{macro}
%
% \subsection{Color expressions}
%
@@ -811,7 +844,6 @@
% \begin{macrocode}
\cs_new_protected:Npx \@@_parse:nN #1#2
{
- \exp_not:N \@@_backend_pickup:N \exp_not:N \l_@@_current_tl
\tl_set:Nx \exp_not:c { l_@@_named_ . _tl }
{ \exp_not:N \@@_model:N \exp_not:N \l_@@_current_tl }
\prop_put:NVx \exp_not:c { l_@@_named_ . _prop }
@@ -827,7 +859,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_parse_aux:nN #1#2
{
- \@@_if_defined:nTF {#1}
+ \color_if_exist:nTF {#1}
{ \@@_parse_set_eq:Nn #2 {#1} }
{ \@@_parse:Nw #2#1 ! \s_@@_stop }
\@@_check_model:N #2
@@ -865,7 +897,7 @@
}
\cs_new_protected:Npn \@@_parse:Nw #1#2 ! #3 \s_@@_stop
{
- \@@_if_defined:nTF {#2}
+ \color_if_exist:nTF {#2}
{
\tl_if_blank:nTF {#3}
{ \@@_parse_set_eq:Nn #1 {#2} }
@@ -938,7 +970,7 @@
% \begin{macrocode}
\cs_new_protected:Npn \@@_parse_loop:nn #1#2
{
- \@@_if_defined:nTF {#2}
+ \color_if_exist:nTF {#2}
{
\@@_extract:nNN {#2} \l_@@_next_model_tl \l_@@_next_value_tl
\tl_if_eq:NNF \l_@@_model_tl \l_@@_next_model_tl
@@ -1255,6 +1287,70 @@
% \end{macro}
% \end{macro}
%
+% \begin{macro}{\@@_parse_model_cmy:w}
+% Simply pass data to the conversion functions.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_model_cmy:w #1 , #2 , #3 , #4 \s_@@_stop
+ {
+ { cmyk }
+ { \@@_convert_rgb_cmyk:nnn {#1} {#2} {#3} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_model_tHsb:w}
+% \begin{macro}{\@@_parse_model_tHsb:n}
+% \begin{macro}{\@@_parse_model_tHsb:nw}
+% There are three stages to the process here: bring the |tH| argument into
+% the normal range, divide through to get to |hsb| and finally convert that
+% to |rgb|. The final stage can be delegated to the parsing function for
+% |hsb|, and the conversion from |Hsb| to |hsb| is trivial, so the main focus
+% here is the first stage. We use a simple expandable loop to do the work,
+% and we implement the equation given in the \pkg{xcolor} manual
+% (number~85 there) as a simple expression.
+% \begin{macrocode}
+\cs_new:Npn \@@_parse_model_tHsb:w #1 , #2 , #3 , #4 \s_@@_stop
+ {
+ \exp_args:Ne \@@_parse_model_hsb:nnn
+ { \@@_parse_model_tHsb:n {#1} } {#2} {#3}
+ }
+\cs_new:Npn \@@_parse_model_tHsb:n #1
+ {
+ \@@_parse_model_tHsb:nw {#1}
+ 0 , 0 ;
+ 60 , 30 ;
+ 120 , 60 ;
+ 180 , 120 ;
+ 210 , 180 ;
+ 240 , 240 ;
+ 360 , 360 ;
+ \q_recursion_tail , ;
+ \q_recursion_stop
+ }
+\cs_new:Npn \@@_parse_model_tHsb:nw #1 #2 , #3 ; #4 , #5 ;
+ {
+ \quark_if_recursion_tail_stop_do:nn {#4} { 0 }
+ \fp_compare:nNnTF {#1} > {#4}
+ { \@@_parse_model_tHsb:nw {#1} #4 , #5 ; }
+ {
+ \use_i_delimit_by_q_recursion_stop:nw
+ { \fp_eval:n { ((#1 - #2) / (#4 - #2) * (#5 - #3) + #3) / 360 } }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\@@_parse_model_&spot:w}
+% We cannot extract data here from that passed by \pkg{xcolor}, so
+% we fall back on a black tint.
+% \begin{macrocode}
+\cs_new:cpn { @@_parse_model_&spot:w } #1 , #2 \s_@@_stop
+ { { gray } { #1 } }
+% \end{macrocode}
+% \end{macro}
+%
% \subsection{Selecting colors (and color models)}
%
% \begin{variable}{\l_color_fixed_model_tl}
@@ -1738,7 +1834,7 @@
}
\cs_new_protected:Npn \color_set_eq:nn #1#2
{
- \@@_if_defined:nTF {#2}
+ \color_if_exist:nTF {#2}
{
\tl_clear_new:c { l_@@_named_ #1 _tl }
\prop_clear_new:c { l_@@_named_ #1 _prop }
@@ -2932,7 +3028,7 @@
#1 { color } { show }
{#2}
{
- \@@_if_defined:nT {#2}
+ \color_if_exist:nT {#2}
{
\exp_args:Nv \@@_show:n { l_@@_named_ #2 _tl }
\prop_map_function:cN
@@ -3048,6 +3144,12 @@
\\ \\
key~was~given~with~the~correct~information.
}
+\msg_new:nnn { color } { unhandled-model }
+ {
+ Unhandled~color~model~in~LaTeX2e~value~"#1":
+ \\ \\
+ falling~back~on~grayscale.
+ }
\msg_new:nnnn { color } { unknown-color }
{ Unknown~color~'#1'. }
{
@@ -3087,7 +3189,7 @@
LaTeX~has~been~asked~to~create~a~new~color~model~called~'#1',~
but~this~type~of~model~was~never~set~up.
}
-\prop_gput:Nnn \g_msg_module_name_prop { color } { LaTeX3 }
+\prop_gput:Nnn \g_msg_module_name_prop { color } { LaTeX }
\prop_gput:Nnn \g_msg_module_type_prop { color } { }
% \end{macrocode}
%