summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3backend/l3backend-color.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'macros/latex/contrib/l3backend/l3backend-color.dtx')
-rw-r--r--macros/latex/contrib/l3backend/l3backend-color.dtx380
1 files changed, 199 insertions, 181 deletions
diff --git a/macros/latex/contrib/l3backend/l3backend-color.dtx b/macros/latex/contrib/l3backend/l3backend-color.dtx
index 7166fb693d..6f766bc88a 100644
--- a/macros/latex/contrib/l3backend/l3backend-color.dtx
+++ b/macros/latex/contrib/l3backend/l3backend-color.dtx
@@ -43,7 +43,7 @@
% }^^A
% }
%
-% \date{Released 2022-04-14}
+% \date{Released 2022-04-20}
%
% \maketitle
%
@@ -60,9 +60,10 @@
%<@@=color>
% \end{macrocode}
%
-% Color support is split into parts: collecting data from \LaTeXe{}, the color stack, general color, separations, and color for
-% drawings. We have different approaches in each backend, and have some choices
-% to make about \texttt{dvipdfmx}/\XeTeX{} in particular. Whilst it is in some ways
+% Color support is split into parts: collecting data from \LaTeXe{}, the color
+% stack, general color, separations, and color for drawings. We have different
+% approaches in each backend, and have some choices to make about
+% \texttt{dvipdfmx}/\XeTeX{} in particular. Whilst it is in some ways
% convenient to use the same approach in multiple backends, the fact that
% \texttt{dvipdfmx}/\XeTeX{} is PDF-based means it (largely) sticks closer to
% direct PDF output.
@@ -169,119 +170,29 @@
% \subsection{The color stack}
%
% For PDF-based engines, we have a color stack available inside the specials.
-% This is used for concepts beyond color itself: it is needed to manage th graphics
-% state generally. The exact form depends on the engine, and for
-% \texttt{dvipdfmx}/\XeTeX{} the backend version.
+% This is used for concepts beyond color itself: it is needed to manage the
+% graphics state generally. Although \texttt{dvipdfmx}/\XeTeX{} have multiple
+% color stacks in recent releases, the way these interact with the original
+% single stack and with other graphic state operations means that currently it
+% is not feasible to use the multiple stacks.
%
% \subsubsection{Common code}
%
% \begin{macrocode}
-%<*dvipdfmx|luatex|pdftex|xetex>
+%<*luatex|pdftex>
% \end{macrocode}
%
% \begin{variable}{\l_@@_backend_stack_int}
-% \pdfTeX{}, \LuaTeX{} and recent \texttt{(x)dvipdfmx} have multiple stacks
-% available, and to track which one is in use a variable is required.
+% For tracking which stack is in use where multiple stacks are used:
+% currently just \pdfTeX{}/\LuaTeX{} but at some future stage may also cover
+% \texttt{dvipdfmx}/\XeTeX{}.
% \begin{macrocode}
\int_new:N \l_@@_backend_stack_int
% \end{macrocode}
% \end{variable}
%
% \begin{macrocode}
-%</dvipdfmx|luatex|pdftex|xetex>
-% \end{macrocode}
-%
-% \subsubsection{\texttt{dvipdfmx}/\XeTeX{}}
-%
-% \begin{macrocode}
-%<*dvipdfmx|xetex>
-% \end{macrocode}
-%
-% \begin{macro}{\__kernel_color_backend_stack_init:Nnn}
-% \begin{variable}
-% {\g_@@_backend_stack_int, \c_@@_backend_main_stack_int}
-% In \texttt{(x)dvipdfmx}, the base color stack is not set up, so we have to
-% force that, as well as providing a mechanism more generally.
-% \begin{macrocode}
-\int_new:N \g_@@_backend_stack_int
-\cs_new_protected:Npx \__kernel_color_backend_stack_init:Nnn #1#2#3
- {
- \int_gincr:N \exp_not:N \g_@@_backend_stack_int
- \int_const:Nn #1 { \exp_not:N \g_@@_backend_stack_int }
- \use:x
- {
- \__kernel_backend_first_shipout:n
- {
- \__kernel_backend_literal:n
- {
- pdfcolorstackinit ~
- \exp_not:N \int_use:N \exp_not:N \g_@@_backend_stack_int
- \c_space_tl
- \exp_not:N \tl_if_blank:nF {#2} { #2 ~ }
- (#3)
- }
- }
- }
- }
-\cs_if_exist:cTF { main@pdfcolorstack }
- {
- \int_set:Nn \l_@@_backend_stack_int
- { \int_use:c { main@pdfcolorstack } }
- }
- {
- \__kernel_color_backend_stack_init:Nnn \c_@@_backend_main_stack_int
- { page ~ direct } { 0 ~ g ~ 0 ~ G }
- \int_set_eq:NN \l_@@_backend_stack_int
- \c_@@_backend_main_stack_int
- \int_const:cn { main@pdfcolorstack } { \c_@@_backend_main_stack_int }
- }
-% \end{macrocode}
-% The backend automatically restores the stack color from the \enquote{classical}
-% approach (\texttt{pdf:bcolor}) after a scope. That will be an issue for us, so
-% we manually ensure that the one we are using is inserted.
-% \begin{macrocode}
-\cs_gset_protected:Npn \__kernel_backend_scope_end:
- {
- \__kernel_backend_literal:n { x:grestore }
- \__kernel_backend_literal:x
- {
- pdfcolorstack ~
- \int_use:N \g_@@_backend_stack_int \c_space_tl current
- }
- }
-% \end{macrocode}
-% \end{variable}
-% \end{macro}
-%
-% \begin{macro}{\__kernel_color_backend_stack_push:nn, \__kernel_color_backend_stack_push:nx}
-% \begin{macro}{\__kernel_color_backend_stack_pop:n}
-% Simple enough but needs a version check.
-% \begin{macrocode}
-\cs_new_protected:Npn \__kernel_color_backend_stack_push:nn #1#2
- {
- \__kernel_backend_literal:x
- {
- pdfcolorstack ~
- \int_eval:n {#1} ~
- push ~ (#2)
- }
- }
-\cs_generate_variant:Nn \__kernel_color_backend_stack_push:nn { nx }
-\cs_new_protected:Npn \__kernel_color_backend_stack_pop:n #1
- {
- \__kernel_backend_literal:x
- {
- pdfcolorstack ~
- \int_eval:n {#1} ~
- pop
- }
- }
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macrocode}
-%</dvipdfmx|xetex>
+%</luatex|pdftex>
% \end{macrocode}
%
% \subsubsection{\LuaTeX and \pdfTeX{}}
@@ -309,7 +220,7 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\__kernel_color_backend_stack_push:nn, \__kernel_color_backend_stack_push:nx}
+% \begin{macro}{\__kernel_color_backend_stack_push:nn}
% \begin{macro}{\__kernel_color_backend_stack_pop:n}
% \begin{macrocode}
\cs_new_protected:Npn \__kernel_color_backend_stack_push:nn #1#2
@@ -322,7 +233,6 @@
%</pdftex>
\int_eval:n {#1} ~ push ~ {#2}
}
-\cs_generate_variant:Nn \__kernel_color_backend_stack_push:nn { nx }
\cs_new_protected:Npn \__kernel_color_backend_stack_pop:n #1
{
%<*luatex>
@@ -392,7 +302,7 @@
% \subsubsection{\LuaTeX{} and \pdfTeX{}}
%
% \begin{macrocode}
-%<*dvipdfmx|luatex|pdftex|xetex>
+%<*luatex|pdftex>
% \end{macrocode}
%
% \begin{variable}{\l_@@_backend_fill_tl, \l_@@_backend_stroke_tl}
@@ -431,6 +341,45 @@
% \end{macro}
% \end{macro}
%
+% \begin{macrocode}
+%</luatex|pdftex>
+% \end{macrocode}
+%
+% \subsubsection{\texttt{dvipmdfx}/\XeTeX{}}
+%
+% These backends have the most possible approaches: it recognises both
+% \texttt{dvips}-based color specials and its own format, plus one can
+% include PDF statements directly. Recent releases also have a color stack
+% approach similar to \pdfTeX{}. Of the stack methods, the dedicated
+% the most versatile is the latter as it can cover all of the use cases
+% we have. However, at present this interacts problematically with any color
+% on the original stack. We therefore stick to a single-stack approach here.
+%
+% \begin{macrocode}
+%<*dvipdfmx|xetex>
+% \end{macrocode}
+%
+% \begin{macro}
+% {
+% \@@_backend_select:n ,
+% \@@_backend_select_cmyk:n ,
+% \@@_backend_select_gray:n ,
+% \@@_backend_select_rgb:n
+% }
+% \begin{macro}{\@@_backend_reset:}
+% Using the single stack is relatively easy as there is only one route.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_select:n #1
+ { \__kernel_backend_literal:n { pdf : bc ~ [ #1 ] } }
+\cs_new_eq:NN \@@_backend_select_cmyk:n \@@_backend_select:n
+\cs_new_eq:NN \@@_backend_select_gray:n \@@_backend_select:n
+\cs_new_eq:NN \@@_backend_select_rgb:n \@@_backend_select:n
+\cs_new_protected:Npn \@@_backend_reset:
+ { \__kernel_backend_literal:n { pdf : ec } }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
% \begin{macro}{\@@_backend_select_named:n}
% For classical named colors, the only value we should get is |Black|.
% \begin{macrocode}
@@ -446,19 +395,9 @@
% \end{macro}
%
% \begin{macrocode}
-%</dvipdfmx|luatex|pdftex|xetex>
+%</dvipdfmx|xetex>
% \end{macrocode}
%
-% \subsubsection{\texttt{dvipmdfx}/\XeTeX{}}
-%
-% These backends have the most possible approaches: it recognises both
-% \texttt{dvips}-based color specials and it's own format, plus one can
-% include PDF statements directly. Recent releases also have a color stack
-% approach similar to \pdfTeX{}. Of the stack methods, the dedicated
-% the most versatile is the latter as it can cover all of the use cases
-% we have. Thus it is used in preference to the \texttt{dvips}-style interface
-% or the \enquote{native} color specials (which have only one stack).
-%
% \subsection{Separations}
%
% Here, life gets interesting and we need essentially one approach per
@@ -867,24 +806,53 @@
% \@@_backend_select_devicen:nn ,
% \@@_backend_select_iccbased:nn
% }
-% Although \texttt{(x)dvipdfmx} has a built-in approach to color spaces, that
-% can't be used with the generic color stacks. So we take an approach in which
-% we share the same code as for \pdfTeX{}.
% \begin{macrocode}
+%<*dvipdfmx|xetex>
+\cs_new_protected:Npn \@@_backend_select_separation:nn #1#2
+ { \__kernel_backend_literal:x { pdf : bc ~ \pdf_object_ref:n {#1} ~ [ #2 ] } }
+%</dvipdfmx|xetex>
+%<*luatex|pdftex>
\cs_new_protected:Npn \@@_backend_select_separation:nn #1#2
{ \@@_backend_select:nn { /#1 ~ cs ~ #2 ~ scn } { /#1 ~ CS ~ #2 ~ SCN } }
+%</luatex|pdftex>
\cs_new_eq:NN \@@_backend_select_devicen:nn \@@_backend_select_separation:nn
\cs_new_eq:NN \@@_backend_select_iccbased:nn \@@_backend_select_separation:nn
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_backend_init_resource:n}
+% Resource initiation comes up a few times. For \texttt{dvipdfmx}/\XeTeX{},
+% we skip this as at present it's handled by the backend.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_init_resource:n #1
+ {
+%<*luatex|pdftex>
+ \bool_lazy_and:nnT
+ { \cs_if_exist_p:N \pdfmanagement_if_active_p: }
+ { \pdfmanagement_if_active_p: }
+ {
+ \use:x
+ {
+ \pdfmanagement_add:nnn
+ { Page / Resources / ColorSpace }
+ { #1 }
+ { \pdf_object_ref_last: }
+ }
+ }
+%</luatex|pdftex>
+ }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\@@_backend_separation_init:nnnnn}
% \begin{macro}{\@@_backend_separation_init:nn}
% \begin{macro}{\@@_backend_separation_init_CIELAB:nnn}
% Initialising the PDF structures needs two parts: creating an object
% containing the \enquote{real} name of the Separation, then adding a reference
% to that to each page. We use a separate object for the tint transformation
-% following the model in the PDF reference.
+% following the model in the PDF reference. The object here for the color
+% needs to be named as that way it's accessible to
+% \texttt{dvipdfmx}/\XeTeX{}.
% \begin{macrocode}
\cs_new_protected:Npn \@@_backend_separation_init:nnnnn #1#2#3#4#5
{
@@ -898,23 +866,16 @@
}
\exp_args:Nx \@@_backend_separation_init:nn
{ \str_convert_pdfname:n {#1} } {#2}
- \bool_lazy_and:nnT
- { \cs_if_exist_p:N \pdfmanagement_if_active_p: }
- { \pdfmanagement_if_active_p: }
- {
- \use:x
- {
- \pdfmanagement_add:nnn
- { Page / Resources / ColorSpace }
- { color \int_use:N \g_@@_model_int }
- { \pdf_object_ref_last: }
- }
- }
+ \@@_backend_init_resource:n { color \int_use:N \g_@@_model_int }
}
\cs_new_protected:Npn \@@_backend_separation_init:nn #1#2
{
- \pdf_object_unnamed_write:nx { array }
- { /Separation /#1 ~ #2 ~ \pdf_object_ref_last: }
+ \use:x
+ {
+ \pdf_object_new:nn { color \int_use:N \g_@@_model_int } { array }
+ \pdf_object_write:nn { color \int_use:N \g_@@_model_int }
+ { /Separation /#1 ~ #2 ~ \pdf_object_ref_last: }
+ }
\prop_gput:Nnx \g_@@_backend_colorant_prop { /#1 }
{ \pdf_object_ref_last: }
}
@@ -978,26 +939,19 @@
}
{ {#3} }
}
- \pdf_object_unnamed_write:nx { array }
- {
- /DeviceN ~
- [ ~ #1 ~ ] ~
- #2 ~
- \pdf_object_ref_last:
- \@@_backend_devicen_colorants:n {#1}
- }
- \bool_lazy_and:nnT
- { \cs_if_exist_p:N \pdfmanagement_if_active_p: }
- { \pdfmanagement_if_active_p: }
+ \use:x
{
- \use:x
+ \pdf_object_new:nn { color \int_use:N \g_@@_model_int } { array }
+ \pdf_object_write:nn { color \int_use:N \g_@@_model_int }
{
- \pdfmanagement_add:nnn
- { Page / Resources / ColorSpace }
- { color \int_use:N \g_@@_model_int }
- { \pdf_object_ref_last: }
+ /DeviceN ~
+ [ ~ #1 ~ ] ~
+ #2 ~
+ \pdf_object_ref_last:
+ \@@_backend_devicen_colorants:n {#1}
}
}
+ \@@_backend_init_resource:n { color \int_use:N \g_@@_model_int }
}
\cs_new:Npn \@@_backend_devicen_init:w #1 ~ #2 \s_@@_stop
{
@@ -1029,23 +983,14 @@
}
\pdf_object_unnamed_write:nx { array }
{ /ICCBased ~ \pdf_object_ref:n { @@_icc_ #1 } }
- \cs_if_exist:NT \pdfmanagement_add:nnn
- {
- \use:x
- {
- \pdfmanagement_add:nnn { Page / Resources / ColorSpace }
- { color \int_use:N \g_@@_model_int }
- { ~ \pdf_object_ref_last: }
- }
- }
+ \@@_backend_init_resource:n { color \int_use:N \g_@@_model_int }
}
% \end{macrocode}
% \end{macro}
-
%
% \begin{macro}{\@@_backend_iccbased_device:nnn}
% This is very similar to setting up a color space: the only part we
-% skip is adding it to the page resources.
+% add to the page resources differently.
% \begin{macrocode}
\cs_new_protected:Npn \@@_backend_iccbased_device:nnn #1#2#3
{
@@ -1060,16 +1005,7 @@
}
\pdf_object_unnamed_write:nx { array }
{ /ICCBased ~ \pdf_object_ref:n { @@_icc_ #1 } }
- \cs_if_exist:NT \pdfmanagement_add:nnn
- {
- \use:x
- {
- \pdfmanagement_add:nnn
- { Page / Resources / ColorSpace }
- { Default #2 }
- { \pdf_object_ref_last: }
- }
- }
+ \@@_backend_init_resource:n { Default #2 }
}
% \end{macrocode}
% \end{macro}
@@ -1080,13 +1016,78 @@
%
% \subsection{Fill and stroke color}
%
-% Here, \texttt{dvipdfmx}/\XeTeX{} follows \LuaTeX{} and \pdfTeX{},
-% while for \texttt{dvips}
+% Here, \texttt{dvipdfmx}/\XeTeX{} we write direct PDF specials for the fill,
+% and only use the stack for the stroke color (see above for comments on why
+% we cannot use multiple stacks with these backends). \LuaTeX{} and \pdfTeX{}
+% have mutiple stacks that can deal with fill and stroke. 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|luatex|pdftex|xetex>
+%<*dvipdfmx|xetex>
+% \end{macrocode}
+%
+% \begin{macro}
+% {
+% \@@_backend_fill:n ,
+% \@@_backend_fill_cmyk:n ,
+% \@@_backend_fill_gray:n ,
+% \@@_backend_fill_rgb:n ,
+% \@@_backend_stroke:n ,
+% \@@_backend_stroke_cmyk:n ,
+% \@@_backend_stroke_gray:n ,
+% \@@_backend_stroke_rgb:n
+% }
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_fill:n #1
+ { \__kernel_backend_literal:n { pdf : bc ~ fill ~ [ #1 ] } }
+\cs_new_eq:NN \@@_backend_fill_cmyk:n \@@_backend_fill:n
+\cs_new_eq:NN \@@_backend_fill_gray:n \@@_backend_fill:n
+\cs_new_eq:NN \@@_backend_fill_rgb:n \@@_backend_fill:n
+\cs_new_protected:Npn \@@_backend_stroke:n #1
+ { \__kernel_backend_literal:n { pdf : bc ~ stroke ~ [ #1 ] } }
+\cs_new_eq:NN \@@_backend_stroke_cmyk:n \@@_backend_stroke:n
+\cs_new_eq:NN \@@_backend_stroke_gray:n \@@_backend_stroke:n
+\cs_new_eq:NN \@@_backend_stroke_rgb:n \@@_backend_stroke:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \@@_backend_fill_separation:nn,
+% \@@_backend_stroke_separation:nn,
+% \@@_backend_fill_devicen:nn,
+% \@@_backend_stroke_devicen:nn
+% }
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_backend_fill_separation:nn #1#2
+ {
+ \__kernel_backend_literal:x
+ { pdf : bc ~ fill ~ \pdf_object_ref:n {#1} ~ [ #2 ] }
+ }
+\cs_new_protected:Npn \@@_backend_stroke_separation:nn #1#2
+ {
+ \__kernel_backend_literal:x
+ { pdf : bc ~ stroke ~ \pdf_object_ref:n {#1} ~ [ #2 ] }
+ }
+\cs_new_eq:NN \@@_backend_fill_devicen:nn \@@_backend_fill_separation:nn
+\cs_new_eq:NN \@@_backend_stroke_devicen:nn \@@_backend_stroke_separation:nn
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\@@_backend_fill_reset:, \@@_backend_stroke_reset:}
+% \begin{macrocode}
+\cs_new_eq:NN \@@_backend_fill_reset: \@@_backend_reset:
+\cs_new_eq:NN \@@_backend_stroke_reset: \@@_backend_reset:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</dvipdfmx|xetex>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%<*luatex|pdftex>
% \end{macrocode}
%
% \begin{macro}
@@ -1117,7 +1118,6 @@
\tl_set:Nn \l_@@_backend_fill_tl {#1}
\__kernel_color_backend_stack_push:nn \l_@@_backend_stack_int
{ #1 ~ \l_@@_backend_stroke_tl }
- \group_insert_after:N \@@_backend_reset:
}
\cs_new_protected:Npn \@@_backend_stroke_cmyk:n #1
{ \@@_backend_stroke:n { #1 ~ K } }
@@ -1130,7 +1130,6 @@
\tl_set:Nn \l_@@_backend_stroke_tl {#1}
\__kernel_color_backend_stack_push:nn \l_@@_backend_stack_int
{ \l_@@_backend_fill_tl \c_space_tl #1 }
- \group_insert_after:N \@@_backend_reset:
}
% \end{macrocode}
% \end{macro}
@@ -1152,8 +1151,15 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_backend_fill_reset:, \@@_backend_stroke_reset:}
% \begin{macrocode}
-%</dvipdfmx|luatex|pdftex|xetex>
+\cs_new_eq:NN \@@_backend_fill_reset: \@@_backend_reset:
+\cs_new_eq:NN \@@_backend_stroke_reset: \@@_backend_reset:
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</luatex|pdftex>
% \end{macrocode}
%
% \begin{macrocode}
@@ -1182,7 +1188,6 @@
\cs_new_protected:Npn \@@_backend_fill:n #1
{
\__kernel_backend_literal:n { color~push~ #1 }
- \group_insert_after:N \@@_backend_reset:
}
\cs_new_protected:Npn \@@_backend_stroke_cmyk:n #1
{ \__kernel_backend_postscript:n { /color.sc { #1 ~ setcmykcolor } def } }
@@ -1210,6 +1215,13 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_backend_fill_reset:, \@@_backend_stroke_reset:}
+% \begin{macrocode}
+\cs_new_eq:NN \@@_backend_fill_reset: \@@_backend_reset:
+\cs_new_protected:Npn \@@_backend_stroke_reset: { }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macrocode}
%</dvips>
% \end{macrocode}
@@ -1237,7 +1249,6 @@
\cs_new_protected:Npn \@@_backend_fill:n #1
{
\__kernel_backend_literal:n { color~push~ #1 }
- \group_insert_after:N \@@_backend_reset:
}
% \end{macrocode}
% \end{macro}
@@ -1327,6 +1338,13 @@
% \end{macrocode}
% \end{macro}
%
+% \begin{macro}{\@@_backend_fill_reset:, \@@_backend_stroke_reset:}
+% \begin{macrocode}
+\cs_new_eq:NN \@@_backend_fill_reset: \@@_backend_reset:
+\cs_new_protected:Npn \@@_backend_stroke_reset: { }
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macro}{\@@_backend_devicen_init:nnn, \@@_backend_iccbased_init:nnn}
% No support at present.
% \begin{macrocode}