diff options
author | Norbert Preining <norbert@preining.info> | 2020-07-18 03:01:08 +0000 |
---|---|---|
committer | Norbert Preining <norbert@preining.info> | 2020-07-18 03:01:08 +0000 |
commit | 63c4f21a5716ebbed11926d0bfbb26d656a766ea (patch) | |
tree | c02159e6ceb2453208664129ccda8ff306147328 /macros/latex/contrib/l3experimental/l3color.dtx | |
parent | 4ea983e3d411ade406c09b30ece9139457516b6f (diff) |
CTAN sync 202007180301
Diffstat (limited to 'macros/latex/contrib/l3experimental/l3color.dtx')
-rw-r--r-- | macros/latex/contrib/l3experimental/l3color.dtx | 576 |
1 files changed, 461 insertions, 115 deletions
diff --git a/macros/latex/contrib/l3experimental/l3color.dtx b/macros/latex/contrib/l3experimental/l3color.dtx index 8a87d390b4..91cb13e0b4 100644 --- a/macros/latex/contrib/l3experimental/l3color.dtx +++ b/macros/latex/contrib/l3experimental/l3color.dtx @@ -46,7 +46,7 @@ % }^^A % } % -% \date{Released 2020-06-18} +% \date{Released 2020-07-17} % % \maketitle % @@ -190,9 +190,9 @@ % % \begin{function}{\color_set:nnn} % \begin{syntax} -% \cs{color_set:nnn} \Arg{name} \Arg{model} \Arg{value(s)} +% \cs{color_set:nnn} \Arg{name} \Arg{model(s)} \Arg{value(s)} % \end{syntax} -% Stores the color specification equivalent to the \meta{model} and +% Stores the color specification equivalent to the \meta{model(s)} and % \meta{values} as the \meta{name}. % \end{function} % @@ -225,9 +225,9 @@ % % \begin{function}{\color_select:nn} % \begin{syntax} -% \cs{color_select:nn} \Arg{model} \Arg{value(s)} +% \cs{color_select:nn} \Arg{model(s)} \Arg{value(s)} % \end{syntax} -% Activates the color specification equivalent to the \meta{model} and +% Activates the color specification equivalent to the \meta{model(s)} and % \meta{value(s)} for typeset material. % \end{function} % @@ -237,23 +237,69 @@ % and similar are not influenced by this setting. % \end{variable} % -% \section{Core color representation} +% \section{Multiple color models} % -% To allow data to be handled internally, \pkg{l3color} uses a simple -% representation of color, comprising two \meta{balanced text} entries, the first -% the \meta{model} and the second the \meta{values} given -% \emph{separated by spaces}. -% -% This core representation is produced when parsing color expressions. +% When selecting or setting a color with an explicit model, it is possible +% to give values for more than one model at one time. This is particularly +% useful where automated conversion between models does not give the desired +% outcome. To do this, the list of models and list of values are both subdivided +% using |/| characters (as for the similar function in \pkg{xcolor}). For +% example, to save a color with explicit |cmyk| and |rgb| values, one could +% use +% \begin{verbatim} +% \color_set:nnn { foo } { cmyk / rgb } +% { 0.1 , 0.2 , 0.3 , 0.4 / 0.1, 0.2 , 0.3 } +% \end{verbatim} +% The manually-specified conversion will be used in preference to automated +% calculation whenever the model(s) listed are used: both in expressions and +% when a fixed model is active. % -% \begin{function}{\color_parse:nN} +% Similarly, the same syntax can be applied to directly selecting a color. +% \begin{verbatim} +% \color_select:nn { cmyk / rgb } +% { 0.1 , 0.2 , 0.3 , 0.4 / 0.1, 0.2 , 0.3 } +% \end{verbatim} +% Again, this list is used when a fixed model is active: the first entry is used +% unless there is a fixed model matching one of the other entries. +% +% \section{Exporting color specifications} +% +% The major use of color expressions is in setting typesetting output, but there +% are other places in which some form of color information is required. These +% may need data in a different format or using a different model to the internal +% representation. Thus a set of functions are available to export colors in +% different formats. +% +% Valid export targets are +% \begin{itemize} +% \item \texttt{backend} Two brace groups: the first containing the +% model, the second containing space-separated values appropriate +% for the model; this is the format required by backend functions +% of \pkg{expl3} +% \item \texttt{HTML} Uppercase two-digit hexadecimal values, expressing +% a red-green-blue color; the digits are \emph{not} separated +% \item \texttt{space-sep-cmyk} Space-separated cyan-magenta-yellow-black +% values +% \item \texttt{space-sep-rgb} Space-separated red-green-blue values +% suitable for use as a PDF annotation color +% \end{itemize} +% +% \begin{function}{\color_export:nnN} % \begin{syntax} -% \cs{color_parse:nN} \Arg{color expression} \Arg{tl} +% \cs{color_export:nnN} \Arg{color expression} \Arg{format} \Arg{tl} % \end{syntax} -% Parses the \meta{color expression} as described above, and sets the -% \meta{tl} to the equivalent \meta{core color representation} -% (used at the backend level and based on \texttt{dvips} color -% representation). +% Parses the \meta{color expression} as described earlier, +% then converts to the \meta{format} specified and assigns the data to the +% \meta{tl}. +% \end{function} +% +% \begin{function}{\color_export:nnN} +% \begin{syntax} +% \cs{color_export:nnnN} \Arg{model} \Arg{value(s)} \Arg{format} \Arg{tl} +% \end{syntax} +% Expresses the combination of \meta{model} and \meta{value(s)} in an +% internal representation, then converts to the \meta{format} specified and +% assigns the data to the \meta{tl}. % \end{function} % % \section{Spot colors} @@ -275,7 +321,7 @@ % % \begin{macrocode} %<*package> -\ProvidesExplPackage{l3color}{2020-06-18}{} +\ProvidesExplPackage{l3color}{2020-07-17}{} {L3 Experimental color support} %</package> % \end{macrocode} @@ -297,8 +343,8 @@ % functions). % % Since there is no need to manipulate colors \emph{en masse}, each is stored -% in a separate token list variable, rather than the alternative of using a -% single property list for all names. +% in a two-part structure: a \texttt{prop} for the colors themselves, and a +% \texttt{tl} for the default model for each color. % % \subsection{Setup} % @@ -323,42 +369,37 @@ % \begin{macrocode} \prg_new_conditional:Npnn \@@_if_defined:n #1 { T, F, TF } { - \tl_if_exist:cTF { l_@@_named_ #1 _tl } + \prop_if_exist:cTF { l_@@_named_ #1 _prop } \prg_return_true: \prg_return_false: } % \end{macrocode} % \end{macro} % +% \begin{macro}[EXP]{\@@_model:N, \@@_values:N} +% Simple abstractions. +% \begin{macrocode} +\cs_new:Npn \@@_model:N #1 { \exp_after:wN \use_i:nn #1 } +\cs_new:Npn \@@_values:N #1 { \exp_after:wN \use_ii:nn #1 } +% \end{macrocode} +% \end{macro} +% % \begin{macro}{\@@_extract:nNN, \@@_extract:VNN} -% \begin{macro}{\@@_extract:NNnn} -% Split the model and color from a named color, and store the two. No test -% for the existence of the color: that is assumed to be the case (this -% is internal only). Somewhat \enquote{old-fashioned} but should be quite -% fast. +% Recover the values for the standard model for a color. % \begin{macrocode} \cs_new_protected:Npn \@@_extract:nNN #1#2#3 { - \exp_after:wN \exp_after:wN \exp_after:wN - \@@_extract:NNnn - \exp_after:wN \exp_after:wN \exp_after:wN #2 - \exp_after:wN \exp_after:wN \exp_after:wN #3 - \cs:w l_@@_named_ #1 _tl \cs_end: + \tl_set_eq:Nc #2 { l_@@_named_ #1 _tl } + \prop_get:cVN { l_@@_named_ #1 _prop } #2 #3 } \cs_generate_variant:Nn \@@_extract:nNN { V } -\cs_new_protected:Npn \@@_extract:NNnn #1#2#3#4 - { - \tl_set:Nn #1 {#3} - \tl_set:Nn #2 {#4} - } % \end{macrocode} % \end{macro} -% \end{macro} % % \subsection{Model conversion} % % \begin{macro}{\@@_convert:nnN, \@@_convert:VVN} -% \begin{macro}{\@@_convert:nnnN} +% \begin{macro}{\@@_convert:nnnN, \@@_convert:nVnN, \@@_convert:nnVN} % \begin{macro}[aux, EXP] % { % \@@_convert_gray_rgb:w @@ -383,7 +424,7 @@ \tl_set:Nx #4 { \use:c { @@_convert_ #1 _ #2 :w } #3 ~ 0 ~ 0 ~ 0 \s_@@_stop } } -\cs_generate_variant:Nn \@@_convert:nnnN { nnV } +\cs_generate_variant:Nn \@@_convert:nnnN { nV , nnV } \cs_new:Npn \@@_convert_gray_rgb:w #1 ~ #2 \s_@@_stop { #1 ~ #1 ~ #1 } \cs_new:Npn \@@_convert_gray_cmyk:w #1 ~ #2 \s_@@_stop @@ -442,12 +483,15 @@ % \end{macrocode} % \end{variable} % -% \begin{macro}{\color_parse:nN} % \begin{macro}{\@@_parse:nN} +% \begin{macro}{\@@_parse_aux:nN} +% \begin{macro}{\@@_parse_eq:Nn} +% \begin{macro}{\@@_parse_eq:nNn} % \begin{macro}{\@@_parse:Nw} % \begin{macro}{\@@_parse_loop_init:Nnn} % \begin{macro}{\@@_parse_loop:w} % \begin{macro}{\@@_parse_loop:nn} +% \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} @@ -462,37 +506,73 @@ % otherwise expands, then starts working through the expression itself. % At the end, we apply the payload. % \begin{macrocode} -\cs_new_protected:Npn \color_parse:nN #1#2 +\cs_new_protected:Npx \@@_parse:nN #1#2 { %<*package> - \@@_backend_pickup:N \l_@@_current_tl - \tl_set_eq:cN { l_@@_named_ . _tl } \l_@@_current_tl + \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 } + \exp_not:c { l_@@_named_ . _tl } + { \exp_not:N \@@_values:N \exp_not:N \l_@@_current_tl } %</package> - \exp_args:Ne \@@_parse:nN { \tl_to_str:n {#1} } #2 + \exp_not:N \exp_args:Ne \exp_not:N \@@_parse_aux:nN + { \exp_not:N \tl_to_str:n {#1} } #2 } % \end{macrocode} % Before going to all of the effort of parsing an expression, these two % precursor functions look for a pre-defined name, either on its own or % with a trailing |!| (which is the same thing). % \begin{macrocode} -\cs_new_protected:Npn \@@_parse:nN #1#2 +\cs_new_protected:Npn \@@_parse_aux:nN #1#2 { - \tl_if_exist:cTF { l_@@_named_ #1 _tl } - { \tl_set_eq:Nc #2 { l_@@_named_ #1 _tl } } + \tl_if_exist:cTF { l_@@_named_ #1 _prop } + { \@@_parse_set_eq:Nn #2 {#1} } { \@@_parse:Nw #2#1 ! \s_@@_stop } \@@_check_model:N #2 } +\cs_new_protected:Npn \@@_parse_set_eq:Nn #1#2 + { + \tl_if_empty:NTF \l_color_fixed_model_tl + { \exp_args:Nv \@@_parse_set_eq:nNn { l_@@_named_ #2 _tl } } + { \exp_args:NV \@@_parse_set_eq:nNn \l_color_fixed_model_tl } + #1 {#2} + } +% \end{macrocode} +% Here, we have to allow for the case where there is a fixed model: +% that can't be swept up by generic conversion as we are dealing with a +% named color. +% \begin{macrocode} +\cs_new_protected:Npn \@@_parse_set_eq:nNn #1#2#3 + { + \prop_get:cnNTF + { l_@@_named_ #3 _prop } {#1} + \l_@@_value_tl + { \tl_set:Nx #2 { {#1} { \l_@@_value_tl } } } + { + \tl_set_eq:Nc \l_@@_model_tl { l_@@_named_ #3 _tl } + \prop_get:cVN { l_@@_named_ #3 _prop } \l_@@_model_tl + \l_@@_value_tl + \@@_convert:nnN + \l_@@_model_tl {#1} \l_@@_value_tl + \tl_set:Nx #2 + { + {#1} + { \l_@@_value_tl } + } + } + } \cs_new_protected:Npn \@@_parse:Nw #1#2 ! #3 \s_@@_stop { \@@_if_defined:nTF {#2} { \tl_if_blank:nTF {#3} - { \tl_set_eq:Nc #1 { l_@@_named_ #2 _tl } } + { \@@_parse_set_eq:Nn #1 {#2} } { \@@_parse_loop_init:Nnn #1 {#2} {#3} } } { \__kernel_msg_error:nnn { color } { unknown-color } {#2} - \tl_set_eq:NN \l_@@_current_tl \l_@@_named_black_tl + \tl_set:Nn \l_@@_current_tl { { gray } { 0 } } } } % \end{macrocode} @@ -562,24 +642,9 @@ \@@_extract:nNN {#2} \l_@@_next_model_tl \l_@@_next_value_tl \tl_if_eq:NNF \l_@@_model_tl \l_@@_next_model_tl { - \str_if_eq:VnT \l_@@_model_tl { gray } - { - \use:x - { - \tl_set:Nn \exp_not:N \l_@@_model_tl - { \l_@@_next_model_tl } - \tl_set:Nn \exp_not:N \l_@@_value_tl - { \l_@@_next_value_tl } - \tl_set:Nn \exp_not:N \l_next_@@_model_tl - { \l_@@_model_tl } - \tl_set:Nn \exp_not:N \l_next_@@_value_tl - { \l_@@_value_tl } - } - } - \@@_convert:VVN - \l_@@_next_model_tl - \l_@@_model_tl - \l_@@_next_value_tl + \str_if_eq:VnTF \l_@@_model_tl { gray } + { \@@_parse_gray:n {#2} } + { \@@_parse_std:n {#2} } } \tl_set:Nx \l_@@_value_tl { @@ -593,6 +658,31 @@ \@@_parse_break:w } } +% \end{macrocode} +% The \texttt{gray} model needs special handling: the models need to be +% swapped: we do that using a dedicated function. +% \begin{macrocode} +\cs_new_protected:Npn \@@_parse_gray:n #1 + { + \tl_set_eq:NN \l_@@_model_tl \l_@@_next_model_tl + \tl_set:Nn \l_@@_next_model_tl { gray } + \exp_args:NnV \@@_convert:nnN { gray } \l_@@_model_tl + \l_@@_value_tl + \prop_get:cVN { l_@@_named_ #1 _prop } \l_@@_model_tl + \l_@@_next_value_tl + } +\cs_new_protected:Npn \@@_parse_std:n #1 + { + \prop_get:cVNF { l_@@_named_ #1 _prop } + \l_@@_model_tl + \l_@@_next_value_tl + { + \@@_convert:VVN + \l_@@_next_model_tl + \l_@@_model_tl + \l_@@_next_value_tl + } + } \cs_new_protected:Npn \@@_parse_break:w #1 \@@_parse_end: { } \cs_new_protected:Npn \@@_parse_end: { } % \end{macrocode} @@ -640,6 +730,9 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}[EXP] % { @@ -814,52 +907,91 @@ % 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:Npn \@@_select: +\cs_new_protected:Npx \@@_select: { - \tl_set_eq:cN { l_@@_named_ . _tl } \l_@@_current_tl - \@@_select: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_clear:N \exp_not:c { l_@@_named_ . _prop } + \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} % % \begin{macro}{\color_select:n} % \begin{macro}{\color_select:nn} +% \begin{macro}{\@@_select_main:Nw, \@@_select_loop:Nw} +% \begin{macro}{\@@_select:nnN} +% \begin{macro}{\@@_select_swap:Nnn} % Parse the input expressions then get the backend to actually activate -% them. +% them. The main complexity here is the need to check through multiple models. +% That is done \enquote{locally} here as the approach is subtly different to +% when different models are being stored. % \begin{macrocode} \cs_new_protected:Npn \color_select:n #1 { - \color_parse:nN {#1} \l_@@_current_tl + \@@_parse:nN {#1} \l_@@_current_tl \@@_select: } \cs_new_protected:Npn \color_select:nn #1#2 { - \@@_direct:nnN {#1} {#2} \l_@@_current_tl + \@@_select_main:Nw \l_@@_current_tl + #1 / / \s_@@_mark #2 / / \s_@@_stop \@@_select: } % \end{macrocode} -% \end{macro} -% \end{macro} -% -% \subsection{Direct model use} -% -% \begin{macro}{\@@_direct:nnN} -% Directly set a color based on a model/value combination. +% If the first color model is the fixed one, or if there is no fixed +% model, we don't need most of the data: just set up and apply the backend +% function. % \begin{macrocode} -\cs_new_protected:Npn \@@_direct:nnN #1#2#3 +\cs_new_protected:Npn \@@_select_main:Nw + #1 #2 / #3 / #4 \s_@@_mark #5 / #6 / #7 \s_@@_stop + { + \@@_select:nnN {#2} {#5} #1 + \bool_lazy_or:nnF + { \tl_if_empty_p:N \l_color_fixed_model_tl } + { \str_if_eq_p:nV {#2} \l_color_fixed_model_tl } + { \@@_select_loop:Nw #1 #3 / #4 \s_@@_mark #6 / #7 \s_@@_stop } + } +% \end{macrocode} +% If a fixed model applies, we need to check each possible value in order. +% If there is no hit at all, fall back on the generic formula-based +% interchange. +% \begin{macrocode} +\cs_new_protected:Npn \@@_select_loop:Nw + #1 #2 / #3 \s_@@_mark #4 / #5 \s_@@_stop + { + \str_if_eq:nVTF {#2} \l_color_fixed_model_tl + { \@@_select:nnN {#2} {#4} #1 } + { + \tl_if_blank:nTF {#2} + { \exp_after:wN \@@_select_swap:Nnn \exp_after:wN #1 #1 } + { \@@_select_loop:Nw #1 #3 \s_@@_mark #5 \s_@@_stop } + } + } +\cs_new_protected:Npn \@@_select:nnN #1#2#3 { \cs_if_exist:cTF { @@_parse_model_ #1 :w } { \tl_set:Nx #3 { \use:c { @@_parse_model_ #1 :w } #2 , 0 , 0 , 0 , 0 \s_@@_stop } - \@@_check_model:N #3 - } - { - \__kernel_msg_error:nnn { color } { unknown-model } {#1} } + { \__kernel_msg_error:nnn { color } { unknown-model } {#1} } + } +\cs_new_protected:Npn \@@_select_swap:Nnn #1#2#3 + { + \@@_convert:nVnN {#2} \l_color_fixed_model_tl {#3} \l_@@_value_tl + \tl_set:Nx #1 + { { \l_color_fixed_model_tl } { \l_@@_value_tl } } } % \end{macrocode} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \subsection{Defining named colors} % @@ -870,44 +1002,113 @@ % \end{macrocode} % \end{variable} % -% \begin{macro}{\@@_store:Nn} -% Store the named color unless it has an invalid name. -% \begin{macrocode} -\cs_new_protected:Npn \@@_store:Nn #1#2 +% \begin{macro}{\color_set:nn} +% \begin{macro}{\@@_set:nnn} +% \begin{macro}{\@@_set:nn} +% \begin{macro}{\@@_set:nnw} +% \begin{macro}{\color_set:nnn} +% \begin{macro}{\@@_set_loop:nw} +% \begin{macro}{\color_set_eq:nn} +% Defining named colors means working through the model list and saving +% both the \enquote{main} color and any equivalents in other models. Even +% if there is only one model, we store a |prop| as well as a |tl|, as there +% could be grouping weirdness, etc. When setting using an expression, +% we need to avoid any fixed model issues, which is done without a group as +% in \pkg{l3keys}. +% \begin{macrocode} +\cs_new_protected:Npn \color_set:nn #1#2 + { + \exp_args:NV \@@_set:nnn + \l_color_fixed_model_tl {#1} {#2} + } +\cs_new_protected:Npn \@@_set:nnn #1#2#3 + { + \tl_clear:N \l_color_fixed_model_tl + \@@_set:nn {#2} {#3} + \tl_set:Nn \l_color_fixed_model_tl {#1} + } +\cs_new_protected:Npn \@@_set:nn #1#2 { - \str_if_eq:nnF {#2} { . } + \str_if_eq:nnF {#1} { . } { - \tl_clear_new:c { l_@@_named_ #2 _tl } - \tl_set_eq:cN { l_@@_named_ #2 _tl } #1 + \@@_parse:nN {#2} \l_@@_named_tl + \tl_clear_new:c { l_@@_named_ #1 _tl } + \tl_set:cx { l_@@_named_ #1 _tl } + { \@@_model:N \l_@@_named_tl } + \prop_clear_new:c { l_@@_named_ #1 _prop } + \prop_put:cvx { l_@@_named_ #1 _prop } { l_@@_named_ #1 _tl } + { \@@_values:N \l_@@_named_tl } + \@@_set:nnw {#1} {#2} #2 ! \s_@@_stop } } % \end{macrocode} -% \end{macro} -% -% \begin{macro}{\color_set:nn} -% \begin{macro}{\color_set:nnn} -% \begin{macro}{\color_set_eq:nn} -% Defining named colors has to include a step to force creation of the -% underlying token list to avoid errors when checking is enabled. +% When setting an expression-based color, there could be multiple model +% data available for one or more of the input colors. Where that is true for +% the \emph{first} named color in an expression, we re-parse the expression +% when they are also parameter-based: only |cmyk|, |gray| and |rgb| make +% any sense here. There is a bit of a performance hit but this should be +% rare and taking place during set-up. % \begin{macrocode} -\cs_new_protected:Npn \color_set:nn #1#2 +\cs_new_protected:Npn \@@_set:nnw #1#2#3 ! #4 \s_@@_stop { - \color_parse:nN {#2} \l_@@_named_tl - \@@_store:Nn \l_@@_named_tl {#1} + \clist_map_inline:nn { cmyk , gray , rgb } + { + \prop_get:cnNT { l_@@_named_ #3 _prop } {##1} \l_@@_internal_tl + { + \prop_if_in:cnF { l_@@_named_ #1 _prop } {##1} + { + \group_begin: + \tl_set:cn { l_@@_named_ #3 _tl } {##1} + \@@_parse:nN {#2} \l_@@_internal_tl + \exp_args:NNNV \group_end: + \tl_set:Nn \l_@@_internal_tl \l_@@_internal_tl + \prop_put:cxx { l_@@_named_ #1 _prop } + { \@@_model:N \l_@@_internal_tl } + { \@@_values:N \l_@@_internal_tl } + } + } + } } \cs_new_protected:Npn \color_set:nnn #1#2#3 { - \@@_direct:nnN {#2} {#3} \l_@@_named_tl - \@@_store:Nn \l_@@_named_tl {#1} + \str_if_eq:nnF {#1} { . } + { + \tl_clear_new:c { l_@@_named_ #1 _tl } + \prop_clear_new:c { l_@@_named_ #1 _prop } + \@@_set_loop:nw {#1} #2 / / \s_@@_mark #3 / / \s_@@_stop + } + } +\cs_new_protected:Npn \@@_set_loop:nw + #1#2 / #3 \s_@@_mark #4 / #5 \s_@@_stop + { + \tl_if_blank:nF {#2} + { + \@@_select:nnN {#2} {#4} \l_@@_named_tl + \tl_set:Nx \l_@@_internal_tl { \@@_model:N \l_@@_named_tl } + \tl_if_empty:cT { l_@@_named_ #1 _tl } + { \tl_set_eq:cN { l_@@_named_ #1 _tl } \l_@@_internal_tl } + \prop_put:cVx { l_@@_named_ #1 _prop } \l_@@_internal_tl + { \@@_values:N \l_@@_named_tl } + \@@_set_loop:nw {#1} #3 \s_@@_mark #5 \s_@@_stop + } } \cs_new_protected:Npn \color_set_eq:nn #1#2 { \@@_if_defined:nTF {#2} { \tl_clear_new:c { l_@@_named_ #1 _tl } + \prop_clear_new:c { l_@@_named_ #1 _prop } \str_if_eq:nnTF {#2} { . } - { \tl_set_eq:cN { l_@@_named_ #1 _tl } \l_@@_current_tl } - { \tl_set_eq:cc { l_@@_named_ #1 _tl } { l_@@_named_ #2 _tl } } + { + \tl_set:cx { l_@@_named_ #1 _tl } + { \@@_model:N \l_@@_current_tl } + \prop_put:cvx { l_@@_named_ #1 _prop } { l_@@_named_ #1 _tl } + { \@@_values:N \l_@@_current_tl } + } + { + \tl_set_eq:cc { l_@@_named_ #1 _tl } { l_@@_named_ #2 _tl } + \prop_set_eq:cc { l_@@_named_ #1 _prop } { l_@@_named_ #2 _prop } + } } { \__kernel_msg_error:nnn { color } { unknown-color } {#2} @@ -920,6 +1121,7 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} % % A small set of colors are always defined. % \begin{macrocode} @@ -933,19 +1135,154 @@ \color_set:nnn { blue } { rgb } { 0 , 0 , 1 } % \end{macrocode} % -% \begin{variable}{\l_@@_named_._tl} +% \begin{variable}{\l_@@_named_._prop, \l_@@_named_._tl} % A special named color: this is always defined though not fixed in % definition. % \begin{macrocode} +\prop_new:c { l_@@_named_._prop } \tl_new:c { l_@@_named_._tl } -\tl_set_eq:cN { l_@@_named_._tl } \l_@@_current_tl +\tl_set:cx { l_@@_named_._tl } { \@@_model:N \l_@@_current_tl } +% \end{macrocode} +% \end{variable} +% +% \subsection{Exporting colors} +% +% \begin{macro}{\color_export:nnN} +% \begin{macro}{\color_export:nnnN} +% \begin{macro}{\@@_export:nN} +% \begin{macro}{\@@_export:nnnN} +% \begin{macrocode} +\cs_new_protected:Npn \color_export:nnN #1#2#3 + { + \group_begin: + \tl_if_exist:cT { c_@@_export_ #2 _tl } + { \tl_set_eq:Nc \l_color_fixed_model_tl { c_@@_export_ #2 _tl } } + \@@_parse:nN {#1} #3 + \@@_export:nN {#2} #3 + \exp_args:NNNV \group_end: + \tl_set:Nn #3 #3 + } +\cs_new_protected:Npn \color_export:nnnN #1#2#3#4 + { + \@@_select_main:Nw #4 + #1 / / \s_@@_mark #2 / / \s_@@_stop + \@@_export:nN {#3} #4 + } +\cs_new_protected:Npn \@@_export:nN #1#2 + { \exp_after:wN \@@_export:nnnN #2 {#1} #2 } +\cs_new:Npn \@@_export:nnnN #1#2#3#4 + { + \cs_if_exist_use:cF { @@_export_format_ #3 :nnN } + { + \__kernel_msg_error:nnn { color } { unknown-export-format } {#3} + \use_none:nnn + } + {#1} {#2} #4 + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}{\@@_export_format_backend:nnN} +% Simple. +% \begin{macrocode} +\cs_new_protected:Npn \@@_export_format_backend:nnN #1#2#3 + { \tl_set:Nn #3 { {#1} {#2} } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\@@_export:nnnNN} +% A generic auxiliary for cases where only one model is appropriate. +% \begin{macrocode} +\cs_new_protected:Npn \@@_export:nnnNN #1#2#3#4#5 + { + \str_if_eq:nnTF {#2} {#1} + { #5 #4 #3 \s_@@_stop } + { + \@@_convert:nnnN {#2} {#1} {#3} #4 + \exp_after:wN #5 \exp_after:wN #4 + #4 \s_@@_stop + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{variable} +% { +% \c_@@_export_HTML_tl , +% \c_@@_export_space-sep-cmyk_tl , +% \c_@@_export_space-sep-rgb_tl +% } +% \begin{macrocode} +\tl_const:Nn \c_@@_export_HTML_tl { rgb } +\tl_const:cn { c_@@_export_space-sep-cmyk_tl } { cmyk } +\tl_const:cn { c_@@_export_space-sep-rgb_tl } { rgb } % \end{macrocode} % \end{variable} % +% \begin{macro}{\@@_export_format_space-sep-cmyk:nnN} +% \begin{macro}{\@@_export_space-sep-cmyk:Nw} +% \begin{macrocode} +\cs_new_protected:cpx { @@_export_format_space-sep-cmyk:nnN } #1#2#3 + { + \exp_not:N \@@_export:nnnNN { cmyk } {#1} {#2} #3 + \exp_not:c { @@_export_space-sep-cmyk:Nw } + } +\cs_new_protected:cpn { @@_export_space-sep-cmyk:Nw } #1#2 \s_@@_stop + { \tl_set:Nx #1 {#2} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macro} +% { +% \@@_export_format_HTML:nnN , +% \@@_export_format_space-sep-rgb:nnN +% } +% \begin{macro} +% { +% \@@_export_HTML:Nw , +% \@@_export_space-sep-rgb:Nw +% } +% \begin{macro}[EXP]{\@@_export_HTML:n} +% \textsc{html} values must be given in |rgb|: we force conversion if +% required, then do some simple maths. +% \begin{macrocode} +\cs_new_protected:Npn \@@_export_format_HTML:nnN #1#2#3 + { \@@_export:nnnNN { rgb } {#1} {#2}#3 \@@_export_HTML:Nw } +\cs_new_protected:cpx { @@_export_format_space-sep-rgb:nnN } #1#2#3 + { + \exp_not:N \@@_export:nnnNN { rgb } {#1} {#2} #3 + \exp_not:c { @@_export_space-sep-rgb:Nw } + } +\cs_new_protected:Npn \@@_export_HTML:Nw #1#2 ~ #3 ~ #4 \s_@@_stop + { + \tl_set:Nx #1 + { + \@@_export_HTML:n {#2} + \@@_export_HTML:n {#3} + \@@_export_HTML:n {#4} + } + } +\cs_new:Npn \@@_export_HTML:n #1 + { + \fp_compare:nNnTF {#1} = { 0 } + { 00 } + { \int_to_Hex:n { \fp_to_int:n { #1 * 255 } } } + } +\cs_new_protected:cpn { @@_export_space-sep-rgb:Nw } #1#2 \s_@@_stop + { \tl_set:Nx #1 {#2} } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% % \subsection{Diagnostics} % % \begin{macro}{\color_show:n} -% \begin{macro}{\@@_show:nn} +% \begin{macro}{\@@_show:n} % Extract the information about a color and format for the user: the approach % is similar to the keys module here. % \begin{macrocode} @@ -954,17 +1291,20 @@ \msg_show:nnxxxx { LaTeX / color } { show } {#1} { - \@@_if_defined:nTF {#1} - { \exp_last_unbraced:Nv \@@_show:nn { l_@@_named_ #1 _tl } } - { } + \@@_if_defined:nT {#1} + { + \exp_args:Nv \@@_show:n { l_@@_named_ #1 _tl } + \prop_map_function:cN + { l_@@_named_ #1 _prop } + \msg_show_item_unbraced:nn + } } { } { } } -\cs_new:Npn \@@_show:nn #1#2 +\cs_new:Npn \@@_show:n #1 { \msg_show_item_unbraced:nn { model } {#1} - \msg_show_item_unbraced:nn { value } {#2} } % \end{macrocode} % \end{macro} @@ -979,6 +1319,12 @@ LaTeX~has~been~asked~to~use~a~color~named~'#1',~ but~this~has~never~been~defined. } +\__kernel_msg_new:nnnn { color } { unknown-export-format } + { Unknown~export~format~'#1'. } + { + LaTeX~has~been~asked~to~export~a~color~in~format~'#1',~ + but~this~has~never~been~defined. + } \__kernel_msg_new:nnnn { color } { unknown-model } { Unknown~color~model~'#1'. } { |