diff options
author | Karl Berry <karl@freefriends.org> | 2016-10-19 20:38:20 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2016-10-19 20:38:20 +0000 |
commit | 52b787d36c60fda90673669dd2809c95c1fdfca5 (patch) | |
tree | beb7faf87e1ab5be65f7437e500619b20eba20a1 /Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx | |
parent | 97a401ad817da2dafd1069df9d87a28ed39df69b (diff) |
l3 (19oct16)
git-svn-id: svn://tug.org/texlive/trunk@42306 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx | 1160 |
1 files changed, 1106 insertions, 54 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx index cfbcb9bdce3..fc30245ded9 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx @@ -38,7 +38,7 @@ \documentclass[full]{l3doc} %</driver> %<*driver|package> -\GetIdInfo$Id: l3drivers.dtx 6511 2016-05-17 20:20:23Z joseph $ +\GetIdInfo$Id: l3drivers.dtx 6644 2016-08-13 20:22:11Z bruno $ {L3 Experimental drivers} %</driver|package> %<*driver> @@ -167,8 +167,6 @@ % but still require an appreciation of the concepts of PostScript/PDF/SVG % graphic creation. % -% At present \emph{not all drivers are covered} by the following. -% % \begin{function} % { \__driver_draw_begin:, \__driver_draw_end:} % \begin{syntax} @@ -195,7 +193,8 @@ % state and concepts such as color or linewidth are localised to a scope. % This function pair must never be used if an partial path is under % construction: such paths must be entirely contained at one unbroken -% scope level. +% scope level. Note that scopes do not form \TeX{} groups and may not +% be aligned with them. % \end{function} % % \subsection{Path construction} @@ -231,6 +230,16 @@ % without appearing itself. % \end{function} % +% \begin{function}{\__driver_draw_rectangle:nnnn} +% \begin{syntax} +% \cs{__driver_draw_rectangle:nnnn} \Arg{x} \Arg{y} \Arg{width} \Arg{height} +% \end{syntax} +% Adds rectangular path from (\meta{x_1}, \meta{y_1}) of \meta{height} +% and \meta{width}; any active transformation matrix will apply. Note that +% nothing is drawn until a fill or stroke operation is applied, and that the +% path may be discarded or used as a clip without appearing itself. +% \end{function} +% % \begin{function}{\__driver_draw_closepath:} % \begin{syntax} % \cs{__driver_draw_closepath:} @@ -273,9 +282,18 @@ % influenced by the setting for fill color (or the current color if no % specific stroke color is set). The path may also be used for clipping. % For paths which are self-intersecting or comprising multiple parts, the -% determination of which areas are inside the path is made using the nonzero -% winding rule number unless \cs{__driver_draw_eor_bool} is \texttt{true}, -% in which case the even-odd rule is used. +% determination of which areas are inside the path is made using the non-zero +% winding number rule unless the even-odd rule is active. +% \end{function} +% +% \begin{function}{\__driver_draw_nonzero_rule:, \__driver_draw_evenodd_rule:} +% \begin{syntax} +% \cs{__driver_draw_nonzero_rule:} +% \end{syntax} +% Active either the non-zero winding number or the even-odd rule, +% respectively, for determining what is inside a fill or clip area. +% For technical reasons, these command are not influenced by scoping +% and apply on an ongoing basis. % \end{function} % % \begin{function}{\__driver_draw_clip:} @@ -286,7 +304,9 @@ % Indicates that the current path should be used for clipping, such that % any subsequent material outside of the path (but within the current % scope) will not be shown. This command should be given once a path is -% complete but before it is stroked or filled (if appropriate). +% complete but before it is stroked or filled (if appropriate). This +% command is \emph{not} affected by scoping: it applies to exactly one +% path as shown. % \end{function} % % \begin{function}{\__driver_draw_discardpath:} @@ -321,7 +341,7 @@ % $1$\,pt on, $2$\,pt off, $3$\,pt on, and so on. An odd number of entries % means that the last is repeated, for example \texttt{3pt} is equal to % \texttt{3pt, 3pt}. An empty pattern yields a solid line. -% +% % The \meta{phase} specifies an offset at the start of the cycle. For % example, with a pattern \texttt{3pt} a phase of \texttt{1pt} will mean % that the output is $2$\,pt on, $3$\,pt off, $3$\,pt on, $3$\,pt on, @@ -361,6 +381,85 @@ % PDF and PostScript manuals. % \end{function} % +% \subsection{Color} +% +% \begin{function} +% { +% \__driver_draw_color_cmyk:nnnn , +% \__driver_draw_color_cmyk_fill:nnnn , +% \__driver_draw_color_cmyk_stroke:nnnn +% } +% \begin{syntax} +% \cs{__driver_draw_color_cmyk:nnnn} \Arg{cyan} \Arg{magneta} \Arg{yellow} +% \Arg{black} +% \end{syntax} +% Sets the color for drawing to the CMYK values specified, all of which are +% fp expressions which should evaluate to between $0$ and $1$. The +% \texttt{fill} and \texttt{stroke} versions set only the color for those +% operations. Note that the general setting is more efficient with some +% drivers so should in most cases be preferred. +% \end{function} +% +% \begin{function} +% { +% \__driver_draw_color_gray:n , +% \__driver_draw_color_gray_fill:n , +% \__driver_draw_color_gray_stroke:n +% } +% \begin{syntax} +% \cs{__driver_draw_color_gray:n} \Arg{gray} +% \end{syntax} +% Sets the color for drawing to the grayscale value specified, which is +% fp expressions which should evaluate to between $0$ and $1$. The +% \texttt{fill} and \texttt{stroke} versions set only the color for those +% operations. Note that the general setting is more efficient with some +% drivers so should in most cases be preferred. +% \end{function} +% +% \begin{function} +% { +% \__driver_draw_color_rgb:nnn , +% \__driver_draw_color_rgb_fill:nnn , +% \__driver_draw_color_rgb_stroke:nnn +% } +% \begin{syntax} +% \cs{__driver_draw_color_gray:n} \Arg{red} \Arg{green} \Arg{blue} +% \end{syntax} +% Sets the color for drawing to the RGB values specified, all of which are +% fp expressions which should evaluate to between $0$ and $1$. The +% \texttt{fill} and \texttt{stroke} versions set only the color for those +% operations. Note that the general setting is more efficient with some +% drivers so should in most cases be preferred. +% \end{function} +% +% \subsection{Inserting \TeX{} material} +% +% \begin{function}{\__driver_draw_hbox:nnnnnn} +% \begin{syntax} +% \cs{__driver_draw_hbox:Nnnnnnn} \meta{box} +% \Arg{a} \Arg{b} \Arg{c} \Arg{d} \Arg{x} \Arg{y} +% \end{syntax} +% Inserts the \meta{box} as an hbox with the box reference point placed +% at ($x$, $y$). The transformation matrix $[a b c d]$ will be applied +% to the box, allowing it to be in synchronisation with any scaling, rotation +% or skewing applying more generally. Note that \TeX{} material should not +% be inserted directly into a drawing as it will not be in the correct +% location. Also note that as for other drawing elements the box here will +% have no size from a \TeX{} perspective. +% \end{function} +% +% \subsection{Coordinate system transformations} +% +% \begin{function}{\__driver_draw_transformcm:nnnnnn} +% \begin{syntax} +% \cs{__driver_draw_transformcm:nnnnnn} \Arg{a} \Arg{b} \Arg{c} \Arg{d} +% \Arg{x} \Arg{y} +% \end{syntax} +% Applies the transformation matrix $[a b c d]$ and offset vector +% ($x$, $y$) to the current graphic state. This will affect any subsequent +% items in the same scope but not those already given. +% \end{function} +% % \end{documentation} % % \begin{implementation} @@ -440,13 +539,13 @@ % \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:} % Higher-level interfaces for saving and restoring the graphic state. % \begin{macrocode} -\cs_new_protected_nopar:Npx \@@_scope_begin: +\cs_new_protected:Npx \@@_scope_begin: { \cs_if_exist:NTF \luatex_pdfextension:D { \luatex_pdfextension:D save \scan_stop: } { \pdftex_pdfsave:D } } -\cs_new_protected_nopar:Npx \@@_scope_end: +\cs_new_protected:Npx \@@_scope_end: { \cs_if_exist:NTF \luatex_pdfextension:D { \luatex_pdfextension:D restore \scan_stop: } @@ -502,7 +601,7 @@ % There is a dedicated primitive/primitive interface for setting colors. % As with scoping, this approach is not suitable for cached operations. % \begin{macrocode} -\cs_new_protected_nopar:Npx \@@_color_ensure_current: +\cs_new_protected:Npx \@@_color_ensure_current: { \cs_if_exist:NTF \luatex_pdfextension:D { \luatex_pdfextension:D colorstack } @@ -511,7 +610,7 @@ { \exp_not:N \l_@@_current_color_tl } \group_insert_after:N \exp_not:N \@@_color_reset: } -\cs_new_protected_nopar:Npx \@@_color_reset: +\cs_new_protected:Npx \@@_color_reset: { \cs_if_exist:NTF \luatex_pdfextension:D { \luatex_pdfextension:D colorstack } @@ -552,9 +651,9 @@ % \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:} % Scoping is done using direct PDF operations here. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_scope_begin: +\cs_new_protected:Npn \@@_scope_begin: { \@@_literal:n { q } } -\cs_new_protected_nopar:Npn \@@_scope_end: +\cs_new_protected:Npn \@@_scope_end: { \@@_literal:n { Q } } % \end{macrocode} % \end{macro} @@ -591,12 +690,12 @@ % \begin{macro}[aux]{\@@_color_reset:} % Directly set the color using the specials with optimisation support. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_color_ensure_current: +\cs_new_protected:Npn \@@_color_ensure_current: { \tex_special:D { pdf:bcolor~\l_@@_current_color_tl } \group_insert_after:N \@@_color_reset: } -\cs_new_protected_nopar:Npn \@@_color_reset: +\cs_new_protected:Npn \@@_color_reset: { \tex_special:D { pdf:ecolor } } % \end{macrocode} % \end{macro} @@ -624,12 +723,12 @@ { \@ifpackageloaded { color } { - \cs_set_protected_nopar:Npn \@@_color_ensure_current: + \cs_set_protected:Npn \@@_color_ensure_current: { \tex_special:D { color~push~\l_@@_current_color_tl } \group_insert_after:N \@@_color_reset: } - \cs_set_protected_nopar:Npn \@@_color_reset: + \cs_set_protected:Npn \@@_color_reset: { \tex_special:D { color~pop } } } { } @@ -753,9 +852,9 @@ % \begin{macro}[int]{\@@_draw_begin:, \@@_draw_end:} % No special requirements here, so simply set up a drawing scope. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_draw_begin: +\cs_new_protected:Npn \@@_draw_begin: { \@@_draw_scope_begin: } -\cs_new_protected_nopar:Npn \@@_draw_end: +\cs_new_protected:Npn \@@_draw_end: { \@@_draw_scope_end: } % \end{macrocode} % \end{macro} @@ -764,15 +863,16 @@ % In contrast to a general scope, a drawing scope is always done using % the PDF operators so is the same for all relevant drivers. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_draw_scope_begin: +\cs_new_protected:Npn \@@_draw_scope_begin: { \@@_draw_literal:n { q } } -\cs_new_protected_nopar:Npn \@@_draw_scope_end: +\cs_new_protected:Npn \@@_draw_scope_end: { \@@_draw_literal:n { Q } } % \end{macrocode} % \end{macro} % % \begin{macro}[int]{\@@_draw_moveto:nn, \@@_draw_lineto:nn} % \begin{macro}[int]{\@@_draw_curveto:nnnnnn} +% \begin{macro}[int]{\@@_draw_rectangle:nnnn} % Path creation operations all resolve directly to PDF primitive steps, with % only the need to convert to \texttt{bp}. Notice that \texttt{x}-type % expansion is included here to ensure that any variable values are @@ -798,16 +898,32 @@ c } } +\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4 + { + \@@_draw_literal:x + { + \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ + \dim_to_decimal_in_bp:n {#3} ~ \dim_to_decimal_in_bp:n {#4} ~ + re + } + } % \end{macrocode} % \end{macro} % \end{macro} +% \end{macro} % -% \begin{variable}[int]{\@@_draw_eor_bool} +% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:} +% \begin{variable}[aux]{\g_@@_draw_eor_bool} % The even-odd rule here can be implemented as a simply switch. % \begin{macrocode} -\bool_new:N \@@_draw_eor_bool +\cs_new_protected:Npn \@@_draw_evenodd_rule: + { \bool_gset_true:N \g_@@_draw_eor_bool } +\cs_new_protected:Npn \@@_draw_nonzero_rule: + { \bool_gset_false:N \g_@@_draw_eor_bool } +\bool_new:N \g_@@_draw_eor_bool % \end{macrocode} % \end{variable} +% \end{macro} % % \begin{macro}[int] % { @@ -822,28 +938,28 @@ % Converting paths to output is again a case of mapping directly to % PDF operations. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_draw_closepath: +\cs_new_protected:Npn \@@_draw_closepath: { \@@_draw_literal:n { h } } -\cs_new_protected_nopar:Npn \@@_draw_stroke: +\cs_new_protected:Npn \@@_draw_stroke: { \@@_draw_literal:n { S } } -\cs_new_protected_nopar:Npn \@@_draw_closestroke: +\cs_new_protected:Npn \@@_draw_closestroke: { \@@_draw_literal:n { s } } -\cs_new_protected_nopar:Npn \@@_draw_fill: +\cs_new_protected:Npn \@@_draw_fill: { \@@_draw_literal:x - { f \bool_if:NT \@@_draw_eor_bool * } + { f \bool_if:NT \g_@@_draw_eor_bool * } } -\cs_new_protected_nopar:Npn \@@_draw_fillstroke: +\cs_new_protected:Npn \@@_draw_fillstroke: { \@@_draw_literal:x - { B \bool_if:NT \@@_draw_eor_bool * } + { B \bool_if:NT \g_@@_draw_eor_bool * } } -\cs_new_protected_nopar:Npn \@@_draw_clip: +\cs_new_protected:Npn \@@_draw_clip: { \@@_draw_literal:x - { W \bool_if:NT \@@_draw_eor_bool * } + { W \bool_if:NT \g_@@_draw_eor_bool * } } -\cs_new_protected_nopar:Npn \@@_draw_discardpath: +\cs_new_protected:Npn \@@_draw_discardpath: { \@@_draw_literal:n { n } } % \end{macrocode} % \end{macro} @@ -852,7 +968,7 @@ % \begin{macro}[aux]{\@@_draw_dash:n} % \begin{macro}[int]{\@@_draw_linewidth:n} % \begin{macro}[int]{\@@_draw_miterlimit:n} -% \begin{macro}[int]^^A +% \begin{macro}[int] % { % \@@_draw_cap_butt:, \@@_draw_cap_round:, \@@_draw_cap_rectangle:, % \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel: @@ -879,17 +995,17 @@ } \cs_new_protected:Npn \@@_draw_miterlimit:n #1 { \@@_draw_literal:x { \fp_eval:n {#1} ~ M } } -\cs_new_protected_nopar:Npn \@@_draw_cap_butt: +\cs_new_protected:Npn \@@_draw_cap_butt: { \@@_draw_literal:n { 0 ~ J } } -\cs_new_protected_nopar:Npn \@@_draw_cap_round: +\cs_new_protected:Npn \@@_draw_cap_round: { \@@_draw_literal:n { 1 ~ J } } -\cs_new_protected_nopar:Npn \@@_draw_cap_rectangle: +\cs_new_protected:Npn \@@_draw_cap_rectangle: { \@@_draw_literal:n { 2 ~ J } } -\cs_new_protected_nopar:Npn \@@_draw_join_miter: +\cs_new_protected:Npn \@@_draw_join_miter: { \@@_draw_literal:n { 0 ~ j } } -\cs_new_protected_nopar:Npn \@@_draw_join_round: +\cs_new_protected:Npn \@@_draw_join_round: { \@@_draw_literal:n { 1 ~ j } } -\cs_new_protected_nopar:Npn \@@_draw_join_bevel: +\cs_new_protected:Npn \@@_draw_join_bevel: { \@@_draw_literal:n { 2 ~ j } } % \end{macrocode} % \end{macro} @@ -899,14 +1015,45 @@ % \end{macro} % % \begin{macro}[int] -% {\@@_draw_color_cmyk_fill:nnnn, \@@_draw_color_cmyk_stroke:nnnn} +% { +% \@@_draw_color_cmyk:nnnn , +% \@@_draw_color_cmyk_fill:nnnn , +% \@@_draw_color_cmyk_stroke:nnnn +% } +% \begin{macro}[aux]{\@@_draw_color_cmyk_aux:nnnn} % \begin{macro}[int] -% {\@@_draw_color_gray_fill:n, \@@_draw_color_gray_stroke:n} +% { +% \@@_draw_color_gray:n , +% \@@_draw_color_gray_fill:n , +% \@@_draw_color_gray_stroke:n +% } +% \begin{macro}[aux]{\@@_draw_color_gray_aux:n} % \begin{macro}[int] -% {\@@_draw_color_rgb_fill:nnn, \@@_draw_color_rgb_stroke:nnn} +% { +% \@@_draw_color_rgb:nnn , +% \@@_draw_color_rgb_fill:nnn , +% \@@_draw_color_rgb_stroke:nnn +% } +% \begin{macro}[aux]{\@@_draw_color_rgb_aux:nnn} % Yet more fast conversion, all using the FPU to allow for expressions % in numerical input. % \begin{macrocode} +\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn #1#2#3#4 + { + \use:x + { + \@@_draw_color_cmyk_aux:nnnn + { \fp_eval:n {#1} } + { \fp_eval:n {#2} } + { \fp_eval:n {#3} } + { \fp_eval:n {#4} } + } + } +\cs_new_protected:Npn \@@_draw_color_cmyk_aux:nnnn #1#2#3#4 + { + \@@_draw_literal:n + { #1 ~ #2 ~ #3 ~ #4 ~ k ~ #1 ~ #2 ~ #3 ~ #4 ~ K } + } \cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn #1#2#3#4 { \@@_draw_literal:x @@ -925,10 +1072,34 @@ K } } +\cs_new_protected:Npn \@@_draw_color_gray:n #1 + { + \use:x + { \@@_draw_color_gray_aux:n { \fp_eval:n {#1} } } + } +\cs_new_protected:Npn \@@_draw_color_gray_aux:n #1 + { + \@@_draw_literal:n { #1 ~ g ~ #1 ~ G } + } \cs_new_protected:Npn \@@_draw_color_gray_fill:n #1 { \@@_draw_literal:x { \fp_eval:n {#1} ~ g } } \cs_new_protected:Npn \@@_draw_color_gray_stroke:n #1 { \@@_draw_literal:x { \fp_eval:n {#1} ~ G } } +\cs_new_protected:Npn \@@_draw_color_rgb:nnn #1#2#3 + { + \use:x + { + \@@_draw_color_rgb_aux:nnn + { \fp_eval:n {#1} } + { \fp_eval:n {#2} } + { \fp_eval:n {#3} } + } + } +\cs_new_protected:Npn \@@_draw_color_rgb_aux:nnn #1#2#3 + { + \@@_draw_literal:n + { #1 ~ #2 ~ #3 ~ rg ~ #1 ~ #2 ~ #3 ~ RG } + } \cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn #1#2#3 { \@@_draw_literal:x @@ -943,6 +1114,9 @@ % \end{macro} % \end{macro} % \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} % % \begin{macro}[int]{\@@_draw_transformcm:nnnnnn} % The first four arguments here are floats (the affine matrix), the last @@ -1027,11 +1201,12 @@ % % \begin{macro}{\@@_scope_begin:, \@@_scope_end:} % Scope saving/restoring is done directly with no need to worry about the -% transformation matrix. +% transformation matrix. General scoping is only for the graphics stack so +% the lower-cost |gsave|/|grestore| pair are used. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_scope_begin: +\cs_new_protected:Npn \@@_scope_begin: { \tex_special:D { ps:gsave } } -\cs_new_protected_nopar:Npn \@@_scope_end: +\cs_new_protected:Npn \@@_scope_end: { \tex_special:D { ps:grestore } } % \end{macrocode} % \end{macro} @@ -1145,17 +1320,442 @@ % \begin{macro}[aux]{\@@_color_reset:} % Directly set the color using the specials: no optimisation here. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_color_ensure_current: +\cs_new_protected:Npn \@@_color_ensure_current: { \tex_special:D { color~push~\l_@@_current_color_tl } \group_insert_after:N \@@_color_reset: } -\cs_new_protected_nopar:Npn \@@_color_reset: +\cs_new_protected:Npn \@@_color_reset: { \tex_special:D { color~pop } } % \end{macrocode} % \end{macro} % \end{macro} % +% \subsection{Drawing} +% +% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x} +% Literals with no positioning (using |ps:| each one is positioned but +% cut of from everything else, so no good for the stepwise approach needed +% here). +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_literal:n #1 + { \tex_special:D { ps:: ~ #1 } } +\cs_generate_variant:Nn \@@_draw_literal:n { x } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_begin:, \@@_draw_end:} +% The |ps::[begin]| special here deals with positioning but allows us to +% continue on to a matching |ps::[end]|: contrast with |ps:|, which positions +% but where we can't split material between separate calls. The +% |@beginspecial|/|@endspecial| pair are from |special.pro| and correct the +% scale and $y$-axis direction. The reference point at the start of the box +% is saved (as |l3x|/|l3y|) as it is needed when inserting various items. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_begin: + { + \tex_special:D { ps::[begin] } + \tex_special:D { ps::~save } + \tex_special:D { ps::~/l3x~currentpoint~/l3y~exch~def~def } + \tex_special:D { ps::~@beginspecial } + } +\cs_new_protected:Npn \@@_draw_end: + { + \tex_special:D { ps::~@endspecial } + \tex_special:D { ps::~restore } + \tex_special:D { ps::[end] } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_scope_begin:, \@@_draw_scope_end:} +% Scope here may need to contain saved definitions, so the entire memory +% rather than just the graphic state has to be sent to the stack. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_scope_begin: + { \@@_draw_literal:n { save } } +\cs_new_protected:Npn \@@_draw_scope_end: + { \@@_draw_literal:n { restore } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_moveto:nn, \@@_draw_lineto:nn} +% \begin{macro}[int]{\@@_draw_rectangle:nnnn} +% \begin{macro}[int]{\@@_draw_curveto:nnnnnn} +% Path creation operations mainly resolve directly to PostScript primitive +% steps, with only the need to convert to \texttt{bp}. Notice that +% \texttt{x}-type expansion is included here to ensure that any variable +% values are forced to literals before any possible caching. There is +% no native rectangular path command (without also clipping, filling or +% stroking), so that task is done using a small amount of PostScript. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_moveto:nn #1#2 + { + \@@_draw_literal:x + { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ moveto } + } +\cs_new_protected:Npn \@@_draw_lineto:nn #1#2 + { + \@@_draw_literal:x + { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ lineto } + } +\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4 + { + \@@_draw_literal:x + { + \dim_to_decimal_in_bp:n {#4} ~ \dim_to_decimal_in_bp:n {#3} ~ + \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ + moveto~dup~0~rlineto~exch~0~exch~rlineto~neg~0~rlineto~clospath + } + } +\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6 + { + \@@_draw_literal:x + { + \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ + \dim_to_decimal_in_bp:n {#3} ~ \dim_to_decimal_in_bp:n {#4} ~ + \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~ + curveto + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:} +% \begin{variable}[aux]{\g_@@_draw_eor_bool} +% The even-odd rule here can be implemented as a simply switch. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_evenodd_rule: + { \bool_gset_true:N \g_@@_draw_eor_bool } +\cs_new_protected:Npn \@@_draw_nonzero_rule: + { \bool_gset_false:N \g_@@_draw_eor_bool } +\bool_new:N \g_@@_draw_eor_bool +% \end{macrocode} +% \end{variable} +% \end{macro} +% +% \begin{macro}[int] +% { +% \@@_draw_closepath: , +% \@@_draw_stroke: , +% \@@_draw_closestroke: , +% \@@_draw_fill: , +% \@@_draw_fillstroke: , +% \@@_draw_clip: , +% \@@_draw_discardpath: +% } +% \begin{variable}[aux]{\g_@@_draw_clip_bool} +% Unlike PDF, PostScript doesn't track separate colors for strokes and other +% elements. It is also desirable to have the |clip| keyword after a stroke or +% fill. To achieve those outcomes, there is some work to do. For color, if a +% stroke or fill color is defined it is used for the relevant operation, with +% a graphic scope inserted as required. That does mean that once such a color +% is set all further uses inside the same scope have to use scoping: see also +% the color set up functions. For clipping, the required ordering is achieved +% using a \TeX{} switch. All of the operations end with a new path instruction +% as they do not terminate (again in contrast to PDF). +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_closepath: + { \@@_draw_literal:n { closepath } } +\cs_new_protected:Npn \@@_draw_stroke: + { + \@@_draw_literal:n { currentdict~/l3sc~known~{gsave~l3sc}~if } + \@@_draw_literal:n { stroke } + \@@_draw_literal:n { currentdict~/l3sc~known~{grestore}~if } + \bool_if:NT \g_@@_draw_clip_bool + { + \@@_draw_literal:x + { + \bool_if:NT \g_@@_draw_eor_bool { eo } + clip + } + } + \@@_draw_literal:n { newpath } + \bool_gset_false:N \g_@@_draw_clip_bool + } +\cs_new_protected:Npn \@@_draw_closestroke: + { + \@@_draw_closepath: + \@@_draw_stroke: + } +\cs_new_protected:Npn \@@_draw_fill: + { + \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if } + \@@_draw_literal:x + { + \bool_if:NT \g_@@_draw_eor_bool { eo } + fill + } + \@@_draw_literal:n { currentdict~/l3fc~known~{grestore}~if } + \bool_if:NT \g_@@_draw_clip_bool + { + \@@_draw_literal:x + { + \bool_if:NT \g_@@_draw_eor_bool { eo } + clip + } + } + \@@_draw_literal:n { newpath } + \bool_gset_false:N \g_@@_draw_clip_bool + } +\cs_new_protected:Npn \@@_draw_fillstroke: + { + \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if } + \@@_draw_literal:x + { + \bool_if:NT \g_@@_draw_eor_bool { eo } + fill + } + \@@_draw_literal:n { currentdict~/l3fc~known~{grestore}~if } + \@@_draw_literal:n { currentdict~/l3sc~known~{gsave~l3sc}~if } + \@@_draw_literal:n { stroke } + \@@_draw_literal:n { currentdict~/l3sc~known~{grestore}~if } + \bool_if:NT \g_@@_draw_clip_bool + { + \@@_draw_literal:x + { + \bool_if:NT \g_@@_draw_eor_bool { eo } + clip + } + } + \@@_draw_literal:n { newpath } + \bool_gset_false:N \g_@@_draw_clip_bool + } +\cs_new_protected:Npn \@@_draw_clip: + { \bool_gset_true:N \g_@@_draw_clip_bool } +\bool_new:N \g_@@_draw_clip_bool +\cs_new_protected:Npn \@@_draw_discardpath: + { + \bool_if:NT \g_@@_draw_clip_bool + { + \@@_draw_literal:x + { + \bool_if:NT \g_@@_draw_eor_bool { eo } + clip + } + } + \@@_draw_literal:n { newpath } + \bool_gset_false:N \g_@@_draw_clip_bool + } +% \end{macrocode} +% \end{variable} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_dash:nn} +% \begin{macro}[aux]{\@@_draw_dash:n} +% \begin{macro}[int]{\@@_draw_linewidth:n} +% \begin{macro}[int]{\@@_draw_miterlimit:n} +% \begin{macro}[int] +% { +% \@@_draw_cap_butt:, \@@_draw_cap_round:, \@@_draw_cap_rectangle:, +% \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel: +% } +% Converting paths to output is again a case of mapping directly to +% PostScript operations. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_dash:nn #1#2 + { + \@@_draw_literal:x + { + [ ~ + \clist_map_function:nN {#1} \@@_draw_dash:n + ] ~ + \dim_to_decimal_in_bp:n {#2} ~ setdash + } + } +\cs_new:Npn \@@_draw_dash:n #1 + { \dim_to_decimal_in_bp:n {#1} ~ } +\cs_new_protected:Npn \@@_draw_linewidth:n #1 + { + \@@_draw_literal:x + { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth } + } +\cs_new_protected:Npn \@@_draw_miterlimit:n #1 + { \@@_draw_literal:x { \fp_eval:n {#1} ~ setmiterlimit } } +\cs_new_protected:Npn \@@_draw_cap_butt: + { \@@_draw_literal:n { 0 ~ setlinecap } } +\cs_new_protected:Npn \@@_draw_cap_round: + { \@@_draw_literal:n { 1 ~ setlinecap } } +\cs_new_protected:Npn \@@_draw_cap_rectangle: + { \@@_draw_literal:n { 2 ~ setlinecap } } +\cs_new_protected:Npn \@@_draw_join_miter: + { \@@_draw_literal:n { 0 ~ setlinejoin } } +\cs_new_protected:Npn \@@_draw_join_round: + { \@@_draw_literal:n { 1 ~ setlinejoin } } +\cs_new_protected:Npn \@@_draw_join_bevel: + { \@@_draw_literal:n { 2 ~ setlinejoin } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[aux]{\_@@_draw_color_reset:} +% \begin{macro}[int] +% { +% \@@_draw_color_cmyk:nnnn , +% \@@_draw_color_cmyk_fill:nnnn , +% \@@_draw_color_cmyk_stroke:nnnn +% } +% \begin{macro}[int] +% { +% \@@_draw_color_gray:n , +% \@@_draw_color_gray_fill:n , +% \@@_draw_color_gray_stroke:n +% } +% \begin{macro}[int] +% { +% \@@_draw_color_rgb:nnn , +% \@@_draw_color_rgb_fill:nnn , +% \@@_draw_color_rgb_stroke:nnn +% } +% To allow color to be defined for strokes and fills separately and to +% respect scoping, the data needs to be stored at the PostScript level. +% We cannot undefine (local) fill/stroke colors once set up but we can +% set them blank to improve performance slightly. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_color_reset: + { + \@@_draw_literal:n { currentdic~/l3fc~known~{ /l3fc~ { } ~def }~if } + \@@_draw_literal:n { currentdic~/l3sc~known~{ /l3sc~ { } ~def }~if } + } +\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn #1#2#3#4 + { + \@@_draw_literal:x + { + \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ + \fp_eval:n {#3} ~ \fp_eval:n {#4} ~ + setcmykcolor ~ + } + \@@_draw_color_reset: + } +\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn #1#2#3#4 + { + \@@_draw_literal:x + { + /l3fc ~ + { + \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ + \fp_eval:n {#3} ~ \fp_eval:n {#4} ~ + setcmykcolor + } ~ + def + } + } +\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4 + { + \__driver_draw_literal:x + { + /l3sc ~ + { + \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ + \fp_eval:n {#3} ~ \fp_eval:n {#4} ~ + setcmykcolor + } ~ + def + } + } +\cs_new_protected:Npn \@@_draw_color_gray:n #1 + { + \@@_draw_literal:x { fp_eval:n {#1} ~ setgray } + \@@_draw_color_reset: + } +\cs_new_protected:Npn \@@_draw_color_gray_fill:n #1 + { \@@_draw_literal:x { /l3fc ~ { \fp_eval:n {#1} ~ setgray } ~ def } } +\cs_new_protected:Npn \@@_draw_color_gray_stroke:n #1 + { \@@_draw_literal:x { /l3sc ~ { \fp_eval:n {#1} ~ setgray } ~ def } } +\cs_new_protected:Npn \@@_draw_color_rgb:nnn #1#2#3 + { + \@@_draw_literal:x + { + \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ + setrgbcolor + } + \@@_draw_color_reset: + } +\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn #1#2#3 + { + \@@_draw_literal:x + { + /l3fc ~ + { + \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ + setrgbcolor + } ~ + def + } + } +\cs_new_protected:Npn \@@_draw_color_rgb_stroke:nnn #1#2#3 + { + \@@_draw_literal:x + { + /l3sc ~ + { + \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ + setrgbcolor + } ~ + def + } + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_transformcm:nnnnnn} +% The first four arguments here are floats (the affine matrix), the last +% two are a displacement vector. Once again, force evaluation to allow for +% caching. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_transformcm:nnnnnn #1#2#3#4#5#6 + { + \@@_draw_literal:x + { + [ + \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ + \fp_eval:n {#3} ~ \fp_eval:n {#4} ~ + \dim_to_decimal_in_bp:n {#5} ~ \dim_to_decimal_in_bp:n {#6} ~ + ] ~ + concat + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_hbox:Nnnnnnn} +% Inside a picture |@beginspecial|/|@endspecial| are active, which is +% normally a good thing but means that the position and scaling will be off +% if the box is inserted directly. Instead, we need to reverse the effect of +% the (normally desirable) shift/scaling within the box. That requires +% knowing where the reference point for the drawing is: saved as |l3x|/|l3y| +% at the start of the picture. Transformation here is relative to the +% drawing origin so has to be done purely in driver code not using \TeX{} +% offsets. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_hbox:Nnnnnnn #1#2#3#4#5#6#7 + { + \@@_scope_begin: + \tex_special:D { ps::[end] } + \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5} {#6} {#7} + \tex_special:D { ps::~72~Resolution~div~72~VResolution~div~neg~scale } + \tex_special:D { ps::~magscale~{1~DVImag~div~dup~scale}~if } + \tex_special:D { ps::~l3x~neg~l3y~neg~translate } + \group_begin: + \box_set_wd:Nn #1 { 0pt } + \box_set_ht:Nn #1 { 0pt } + \box_set_dp:Nn #1 { 0pt } + \box_use:N #1 + \group_end: + \tex_special:D { ps::[begin] } + \@@_scope_end: + } +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</dvips> % \end{macrocode} @@ -1184,9 +1784,9 @@ % A scope in SVG terms is slightly different to the other drivers as % operations have to be \enquote{tied} to these not simply inside them. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_scope_begin: +\cs_new_protected:Npn \@@_scope_begin: { \@@_literal:n { <g> } } -\cs_new_protected_nopar:Npn \@@_scope_end: +\cs_new_protected:Npn \@@_scope_end: { \@@_literal:n { </g> } } % \end{macrocode} % \end{macro} @@ -1352,17 +1952,469 @@ % \begin{macro}[aux]{\@@_color_reset:} % Directly set the color: same as \texttt{dvips}. % \begin{macrocode} -\cs_new_protected_nopar:Npn \@@_color_ensure_current: +\cs_new_protected:Npn \@@_color_ensure_current: { \tex_special:D { color~push~\l_@@_current_color_tl } \group_insert_after:N \@@_color_reset: } -\cs_new_protected_nopar:Npn \@@_color_reset: +\cs_new_protected:Npn \@@_color_reset: { \tex_special:D { color~pop } } % \end{macrocode} % \end{macro} % \end{macro} % +% \subsection{Drawing} +% +% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x} +% The same as the more general literal call. +% \begin{macrocode} +\cs_new_eq:NN \@@_draw_literal:n \@@_literal:n +\cs_generate_variant:Nn \@@_draw_literal:n { x } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_begin:, \@@_draw_end:} +% A drawing needs to be set up such that the co-ordinate system is +% translated. That is done inside a scope, which as described below +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_begin: + { + \@@_draw_scope_begin: + \@@_draw_scope:n { transform="translate({?x},{?y})~scale(1,-1)" } + } +\cs_new_protected:Npn \@@_draw_end: + { \@@_draw_scope_end: } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_scope_begin:, \@@_draw_scope_end:} +% \begin{macro}[aux]{\@@_draw_scope:n, \@@_draw_scope:x} +% \begin{variable}[aux]{\g_@@_draw_scope_int, \l_@@_draw_scope_int} +% Several settings that with other drivers are \enquote{stand alone} have +% to be given as part of a scope in SVG. As a result, there is a need to +% provide a mechanism to automatically close these extra scopes. That is +% done using a dedicated function and a pair of tracking variables. Within +% each graphics scope we use a global variable to do the work, with a group +% used to save the value between scopes. The result is that no direct action +% is needed when creating a scope. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_scope_begin: + { + \int_set_eq:NN + \l_@@_draw_scope_int + \g_@@_draw_scope_int + \group_begin: + \int_gset:Nn \g_@@_draw_scope_int { 0 } + } +\cs_new_protected:Npn \@@_draw_scope_end: + { + \prg_replicate:nn + { \g_@@_draw_scope_int } + { \@@_draw_literal:n { </g> } } + \group_end: + \int_gset_eq:NN + \g_@@_draw_scope_int + \l_@@_draw_scope_int + } +\cs_new_protected:Npn \@@_draw_scope:n #1 + { + \@@_draw_literal:n { <g~ #1 > } + \int_gincr:N \g_@@_draw_scope_int + } +\cs_generate_variant:Nn \@@_draw_scope:n { x } +\int_new:N \g_@@_draw_scope_int +\int_new:N \l_@@_draw_scope_int +% \end{macrocode} +% \end{variable} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_moveto:nn, \@@_draw_lineto:nn} +% \begin{macro}[int]{\@@_draw_rectangle:nnnn} +% \begin{macro}[int]{\@@_draw_curveto:nnnnnn} +% \begin{macro}[aux]{\@@_draw_add_to_path:n} +% \begin{variable}[aux]{\g_@@_draw_path_tl} +% Once again, some work is needed to get path constructs correct. Rather +% then write the values as they are given, the entire path needs to be +% collected up before being output in one go. For that we use a dedicated +% storage routine, which will add spaces as required. Since paths should +% be fully expanded there is no need to worry about the internal +% \texttt{x}-type expansion. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_moveto:nn #1#2 + { + \@@_draw_add_to_path:n + { M ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} } + } +\cs_new_protected:Npn \@@_draw_lineto:nn #1#2 + { + \@@_draw_add_to_path:n + { L ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} } + } +\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4 + { + \@@_draw_add_to_path:n + { + M ~ \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} + h ~ \dim_to_decimal:n {#3} ~ + v ~ \dim_to_decimal:n {#4} ~ + h ~ \dim_to_decimal:n { -#3 } ~ + Z + } + } +\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6 + { + \@@_draw_add_to_path:n + { + C ~ + \dim_to_decimal:n {#1} ~ \dim_to_decimal:n {#2} ~ + \dim_to_decimal:n {#3} ~ \dim_to_decimal:n {#4} ~ + \dim_to_decimal:n {#5} ~ \dim_to_decimal:n {#6} + } + } +\cs_new_protected:Npn \@@_draw_add_to_path:n #1 + { + \tl_gset:Nx \g_@@_draw_path_tl + { + \g_@@_draw_path_tl + \tl_if_empty:NF \g_@@_draw_path_tl { \c_space_tl } + #1 + } + } +\tl_new:N \g_@@_draw_path_tl +% \end{macrocode} +% \end{variable} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:} +% The fill rules here have to be handled as scopes. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_evenodd_rule: + { \@@_draw_scope:n { fill-rule="evenodd" } } +\cs_new_protected:Npn \@@_draw_nonzero_rule: + { \@@_draw_scope:n { fill-rule="nonzero" } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[aux]{\@@_draw_path:n} +% \begin{macro}[int] +% { +% \@@_draw_closepath: , +% \@@_draw_stroke: , +% \@@_draw_closestroke: , +% \@@_draw_fill: , +% \@@_draw_fillstroke: , +% \@@_draw_clip: , +% \@@_draw_discardpath: +% } +% \begin{variable}[aux]{\g_@@_draw_clip_bool} +% \begin{variable}[aux]{\g_@@_draw_path_int} +% Setting fill and stroke effects and doing clipping all has to be done using +% scopes. This means setting up the various requirements in a shared +% auxiliary which deals with the bits and pieces. Clipping paths are reused +% for path drawing: not essential but avoids constructing them twice. +% Discarding a path needs a separate function as it's not quite the same. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_closepath: + { \@@_draw_add_to_path:n { Z } } +\cs_new_protected:Npn \@@_draw_path:n #1 + { + \bool_if:NTF \g_@@_draw_clip_bool + { + \int_gincr:N \g_@@_clip_path_int + \@@_draw_literal:x + { + < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " > + { ?nl } + <path~d=" \g_@@_draw_path_tl "/> { ?nl } + < /clipPath > { ? nl } + < + use~xlink:href = + "\c_hash_str l3path \int_use:N \g_@@_path_int " ~ + #1 + /> + } + \@@_draw_scope:x + { + clip-path = + "url( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int)" + } + } + { + \@@_draw_literal:x + { <path ~ d=" \g_@@_draw_path_tl " ~ #1 /> } + } + \tl_gclear:N \g_@@_draw_path_tl + \bool_gset_false:N \g_@@_draw_clip_bool + } +\int_new:N \g_@@_path_int +\cs_new_protected:Npn \@@_draw_stroke: + { \@@_draw_path:n { style="fill:none" } } +\cs_new_protected:Npn \@@_draw_closestroke: + { + \@@_draw_closepath: + \@@_draw_stroke: + } +\cs_new_protected:Npn \@@_draw_fill: + { \@@_draw_path:n { style="stroke:none" } } +\cs_new_protected:Npn \@@_draw_fillstroke: + { \@@_draw_path:n { } } +\cs_new_protected:Npn \@@_draw_clip: + { \bool_gset_true:N \g_@@_draw_clip_bool } +\bool_new:N \g_@@_draw_clip_bool +\cs_new_protected:Npn \@@_draw_discardpath: + { + \bool_if:NT \g_@@_draw_clip_bool + { + \int_gincr:N \g_@@_clip_path_int + \@@_draw_literal:x + { + < clipPath~id = " l3cp \int_use:N \g_@@_clip_path_int " > + { ?nl } + <path~d=" \g_@@_draw_path_tl "/> { ?nl } + < /clipPath > + } + \@@_draw_scope:x + { + clip-path = + "url( \c_hash_str l3cp \int_use:N \g_@@_clip_path_int)" + } + } + \tl_gclear:N \g_@@_draw_path_tl + \bool_gset_false:N \g_@@_draw_clip_bool + } +% \end{macrocode} +% \end{variable} +% \end{variable} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_dash:nn} +% \begin{macro}[aux]{\@@_draw_dash:n} +% \begin{macro}[aux]{\@@_draw_dash_aux:nn} +% \begin{macro}[int]{\@@_draw_linewidth:n} +% \begin{macro}[int]{\@@_draw_miterlimit:n} +% \begin{macro}[int] +% { +% \@@_draw_cap_butt:, \@@_draw_cap_round:, \@@_draw_cap_rectangle:, +% \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel: +% } +% All of these ideas are properties of scopes in SVG. The only slight +% complexity is converting the dash array properly (doing any required +% maths). +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_dash:nn #1#2 + { + \use:x + { + \@@_draw_dash_aux:nn + { \clist_map_function:nn {#1} \@@_draw_dash:n } + { \dim_to_decimal:n {#2} } + } + } +\cs_new:Npn \@@_draw_dash:n #1 + { , \dim_to_decimal_in_bp:n {#1} } +\cs_new_protected:Npn \@@_draw_dash_aux:nn #1#2 + { + \@@_draw_scope:x + { + stroke-dasharray = + " + \tl_if_empty:oTF { \use_none:n #1 } + { none } + { \use_none:n #1 } + " ~ + stroke-offset=" #2 " + } + } +\cs_new_protected:Npn \@@_draw_linewidth:n #1 + { \@@_draw_scope:x { stroke-width=" \dim_to_decimal:n {#1} " } } +\cs_new_protected:Npn \@@_draw_miterlimit:n #1 + { \@@_draw_scope:x { stroke-miterlimit=" \fp_eval:n {#1} " } } +\cs_new_protected:Npn \@@_draw_cap_butt: + { \@@_draw_scope:n { stroke-linecap="butt" } } +\cs_new_protected:Npn \@@_draw_cap_round: + { \@@_draw_scope:n { stroke-linecap="round" } } +\cs_new_protected:Npn \@@_draw_cap_rectangle: + { \@@_draw_scope:n { stroke-linecap="square" } } +\cs_new_protected:Npn \@@_draw_join_miter: + { \@@_draw_scope:n { stroke-linejoin="miter" } } +\cs_new_protected:Npn \@@_draw_join_round: + { \@@_draw_scope:n { stroke-linejoin="round" } } +\cs_new_protected:Npn \@@_draw_join_bevel: + { \@@_draw_scope:n { stroke-linejoin="bevel" } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int] +% { +% \@@_draw_color_cmyk:nnnn , +% \@@_draw_color_cmyk_fill:nnnn , +% \@@_draw_color_cmyk_stroke:nnnn +% } +% \begin{macro}[int] +% { +% \@@_draw_color_gray:n , +% \@@_draw_color_gray_fill:n , +% \@@_draw_color_gray_stroke:n +% } +% \begin{macro}[int] +% { +% \@@_draw_color_rgb:nnn , +% \@@_draw_color_rgb_fill:nnn , +% \@@_draw_color_rgb_stroke:nnn +% } +% SVG only works with RGB colors, so there is some conversion to +% do. The values also need to be given as percentages, which means a +% little more maths. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_color_cmyk_aux:NNnnnnn #1#2#3#4#5#6 + { + \use:x + { + \@@_draw_color_rgb_auxii:nnn + { \fp_eval:n { -100 * ( (#3) * ( 1 - (#6) ) - 1 ) } } + { \fp_eval:n { -100 * ( (#4) * ( 1 - (#6) ) + #6 - 1 ) } } + { \fp_eval:n { -100 * ( (#5) * ( 1 - (#6) ) + #6 - 1 ) } } + } + #1 #2 + } +\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn + { \@@_draw_color_cmyk_aux:NNnnnnn \c_true_bool \c_true_bool } +\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn + { \@@_draw_color_cmyk_aux:NNnnnnn \c_false_bool \c_true_bool } +\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn + { \@@_draw_color_cmyk_aux:NNnnnnn \c_true_bool \c_false_bool } +\cs_new_protected:Npn \@@_draw_color_gray_aux:NNn #1#2#3 + { + \use:x + { + \@@_draw_color_gray_aux:nNN + { \fp_eval:n { 100 * (#3)} } + } + #1 #2 + } +\cs_new_protected:Npn \@@_draw_color_gray_aux:nNN #1 + { \@@_draw_color_rgb_auxii:nnnNN {#1} {#1} {#1} } +\cs_generate_variant:Nn \@@_draw_color_gray_aux:nNN { x } +\cs_new_protected:Npn \@@_draw_color_gray:n + { \@@_draw_color_gray_aux:NNn \c_true_bool \c_true_bool } +\cs_new_protected:Npn \@@_draw_color_gray_fill:n + { \@@_draw_color_gray_aux:NNn \c_false_bool \c_true_bool } +\cs_new_protected:Npn \@@_draw_color_gray_stroke:n + { \@@_draw_color_gray_aux:NNn \c_true_bool \c_false_bool } +\cs_new_protected:Npn \@@_draw_color_rgb_auxi:NNnnn #1#2#3#4#5 + { + \use:x + { + \@@_draw_color_rgb_auxii:nnnNN + { \fp_eval:n { 100 * (#3) } } + { \fp_eval:n { 100 * (#4) } } + { \fp_eval:n { 100 * (#5) } } + } + #1 #2 + } +\cs_new_protected:Npn \@@_draw_color_rgb_auxii:nnnNN #1#2#3#4#5 + { + \@@_draw_scope:x + { + \bool_if:NT #4 + { + fill = + " + rgb + ( + #1 \c_percent_str , + #2 \c_percent_str , + #3 \c_percent_str + ) + " + \bool_if:NT #5 { ~ } + } + \bool_if:NT #5 + { + stroke = + " + rgb + ( + #1 \c_percent_str , + #2 \c_percent_str , + #3 \c_percent_str + ) + " + } + } + } +\cs_new_protected:Npn \@@_draw_color_rgb:nnn + { \@@_draw_color_rgb_auxi:NNnnn \c_true_bool \c_true_bool } +\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn + { \@@_draw_color_rgb_auxi:NNnnn \c_false_bool \c_true_bool } +\cs_new_protected:Npn \@@_draw_color_rgb_stroke:nnn + { \@@_draw_color_rgb_auxi:NNnnn \c_true_bool \c_false_bool } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_transformcm:nnnnnn} +% The first four arguments here are floats (the affine matrix), the last +% two are a displacement vector. Once again, force evaluation to allow for +% caching. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_transformcm:nnnnnn #1#2#3#4#5#6 + { + \@@_draw_scope:x + { + transform = + " + matrix + ( + \fp_eval:n {#1} , \fp_eval:n {#2} , + \fp_eval:n {#3} , \fp_eval:n {#4} , + \dim_to_decimal:n {#5} , \dim_to_decimal:n {#6} + ) + " + } + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}[int]{\@@_draw_hbox:Nnnnnnn} +% No special savings can be made here: simply displace the box inside +% a scope. As there is nothing to re-box, just make the box passed of +% zero size. +% \begin{macrocode} +\cs_new_protected:Npn \@@_draw_hbox:Nnnnnnn #1#2#3#4#5#6#7 + { + \@@_scope_begin: + \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5} {#6} {#7} + \@@_literal:n + { + < g~ + stroke="none"~ + transform="scale(-1,1)~translate({?x},{?y})~scale(-1,-1)" + > + } + \group_begin: + \box_set_wd:Nn #1 { 0pt } + \box_set_ht:Nn #1 { 0pt } + \box_set_dp:Nn #1 { 0pt } + \box_use:N #1 + \group_end: + \@@_literal:n { </g> } + \@@_scope_end: + } +% \end{macrocode} +% \end{macro} +% % \begin{macrocode} %</dvisvgm> % \end{macrocode} |