[latex3-commits] [l3svn] 01/02: Move dvips driver code to top of source file
noreply at latex-project.org
noreply at latex-project.org
Wed Jun 14 16:45:17 CEST 2017
This is an automated email from the git hooks/post-receive script.
joseph pushed a commit to branch master
in repository l3svn.
commit 09b6f9907c6d4c1463aa3123b05690d0005eb88f
Author: Joseph Wright <joseph.wright at morningstar2.co.uk>
Date: Wed Jun 14 09:52:51 2017 +0100
Move dvips driver code to top of source file
This is going to help with some code sharing.
---
l3kernel/l3drivers.dtx | 2270 ++++++++++++++++++++++++------------------------
1 file changed, 1135 insertions(+), 1135 deletions(-)
diff --git a/l3kernel/l3drivers.dtx b/l3kernel/l3drivers.dtx
index 6fe35dc..36e6f26 100644
--- a/l3kernel/l3drivers.dtx
+++ b/l3kernel/l3drivers.dtx
@@ -487,66 +487,63 @@
%</package>
% \end{macrocode}
%
-% \subsection{\texttt{pdfmode} driver}
+% \subsection{\texttt{dvips} driver}
%
% \begin{macrocode}
-%<*pdfmode>
+%<*dvips>
% \end{macrocode}
%
-% The direct PDF driver covers both \pdfTeX{} and \LuaTeX{}. The latter
-% renames/restructures the driver primitives but this can be handled
-% at one level of abstraction. As such, we avoid using two separate drivers
-% for this material at the cost of some \texttt{x}-type definitions to get
-% everything expanded up-front.
-%
% \subsubsection{Basics}
%
% \begin{macro}[int]{\@@_literal:n}
-% This is equivalent to \verb|\special{pdf:}| but the engine can
-% track it. Without the \texttt{direct} keyword everything is kept in
-% sync: the transformation matrix is set to the current point automatically.
-% Note that this is still inside the text (\texttt{BT} \dots \texttt{ET}
-% block).
+% In the case of \texttt{dvips} there is no build-in saving of the current
+% position, and so some additional PostScript is required to set up the
+% transformation matrix and also to restore it afterwards. Notice the use
+% of the stack to save the current position \enquote{up front} and to
+% move back to it at the end of the process.
% \begin{macrocode}
-\cs_new_protected:Npx \@@_literal:n #1
+\cs_new_protected:Npn \@@_literal:n #1
{
- \cs_if_exist:NTF \luatex_pdfextension:D
- { \luatex_pdfextension:D literal }
- { \pdftex_pdfliteral:D }
- {#1}
+ \tex_special:D
+ {
+ ps:
+ currentpoint~
+ currentpoint~translate~
+ #1 ~
+ neg~exch~neg~exch~translate
+ }
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
-% Higher-level interfaces for saving and restoring the graphic state.
+% \begin{macro}{\@@_scope_begin:, \@@_scope_end:}
+% Scope saving/restoring is done directly with no need to worry about the
+% transformation matrix. General scoping is only for the graphics stack so
+% the lower-cost |gsave|/|grestore| pair are used.
% \begin{macrocode}
-\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:Npx \@@_scope_end:
- {
- \cs_if_exist:NTF \luatex_pdfextension:D
- { \luatex_pdfextension:D restore \scan_stop: }
- { \pdftex_pdfrestore:D }
- }
+\cs_new_protected:Npn \@@_scope_begin:
+ { \tex_special:D { ps:gsave } }
+\cs_new_protected:Npn \@@_scope_end:
+ { \tex_special:D { ps:grestore } }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\@@_matrix:n}
-% Here the appropriate function is set up to insert an affine matrix
-% into the PDF. With \pdfTeX{} and \LuaTeX{} in direct PDF output mode there
-% is a primitive for this, which only needs the rotation/scaling/skew part.
+% \subsection{Driver-specific auxiliaries}
+%
+% \begin{macro}[int, EXP]{\@@_absolute_lengths:n}
+% The \texttt{dvips} driver scales all absolute dimensions based
+% on the output resolution selected and any \TeX{} magnification. Thus
+% for any operation involving absolute lengths there is a correction to
+% make. This is based on \texttt{normalscale} from \texttt{special.pro}
+% but using the stack rather than a definition to save the current matrix.
% \begin{macrocode}
-\cs_new_protected:Npx \@@_matrix:n #1
+\cs_new:Npn \@@_absolute_lengths:n #1
{
- \cs_if_exist:NTF \luatex_pdfextension:D
- { \luatex_pdfextension:D setmatrix }
- { \pdftex_pdfsetmatrix:D }
- {#1}
+ matrix~currentmatrix~
+ Resolution~72~div~VResolution~72~div~scale~
+ DVImag~dup~scale~
+ #1 ~
+ setmatrix
}
% \end{macrocode}
% \end{macro}
@@ -554,24 +551,23 @@
% \subsubsection{Box operations}
%
% \begin{macro}{\@@_box_use_clip:N}
-% The general method is to save the current location, define a clipping path
-% equivalent to the bounding box, then insert the content at the current
-% position and in a zero width box. The \enquote{real} width is then made up
-% using a horizontal skip before tidying up. There are other approaches that
-% can be taken (for example using XForm objects), but the logic here shares
-% as much code as possible and uses the same conversions (and so same
-% rounding errors) in all cases.
+% Much the same idea as for the PDF mode version but with a slightly
+% different syntax for creating the clip path. To avoid any scaling
+% issues we need the absolute length auxiliary here.
% \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_clip:N #1
{
\@@_scope_begin:
\@@_literal:n
{
- 0~
- \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~
- \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
- \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~
- re~W~n
+ \@@_absolute_lengths:n
+ {
+ 0 ~
+ \dim_to_decimal_in_bp:n { \box_dp:N #1 } ~
+ \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
+ \dim_to_decimal_in_bp:n { -\box_ht:N #1 - \box_dp:N #1 } ~
+ rectclip
+ }
}
\hbox_overlap_right:n { \box_use:N #1 }
\@@_scope_end:
@@ -580,57 +576,38 @@
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\@@_box_use_rotate:Nn}
-% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
-% Rotations are set using an affine transformation matrix which therefore
-% requires sine/cosine values not the angle itself. We store the rounded
-% values to avoid rounding twice. There are also a couple of comparisons to
-% ensure that |-0| is not written to the output, as this avoids any issues
-% with problematic display programs. Note that numbers are compared to~$0$
-% after rounding.
+% \begin{macro}{\@@_box_use_rotate:Nn}
+% Rotating using \texttt{dvips} does not require that the box dimensions
+% are altered and has a very convenient built-in operation. Zero rotation
+% must be written as |0| not |-0| so there is a quick test.
% \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
{
\@@_scope_begin:
- \box_set_wd:Nn #1 \c_zero_dim
- \fp_set:Nn \l_@@_cos_fp { round ( cosd ( #2 ) , 5 ) }
- \fp_compare:nNnT \l_@@_cos_fp = \c_zero_fp
- { \fp_zero:N \l_@@_cos_fp }
- \fp_set:Nn \l_@@_sin_fp { round ( sind ( #2 ) , 5 ) }
- \@@_matrix:n
+ \@@_literal:n
{
- \fp_use:N \l_@@_cos_fp \c_space_tl
- \fp_compare:nNnTF \l_@@_sin_fp = \c_zero_fp
- { 0~0 }
- {
- \fp_use:N \l_@@_sin_fp
- \c_space_tl
- \fp_eval:n { -\l_@@_sin_fp }
- }
- \c_space_tl
- \fp_use:N \l_@@_cos_fp
+ \fp_compare:nNnTF {#2} = \c_zero_fp
+ { 0 }
+ { \fp_eval:n { round ( -#2 , 5 ) } } ~
+ rotate
}
\box_use:N #1
\@@_scope_end:
}
-\fp_new:N \l_@@_cos_fp
-\fp_new:N \l_@@_sin_fp
-% \end{macrocode}
-% \end{variable}
% \end{macro}
%
% \begin{macro}{\@@_box_use_scale:Nnn}
-% The same idea as for rotation but without the complexity of signs and
-% cosines.
+% The \texttt{dvips} driver once again has a dedicated operation we can
+% use here.
% \begin{macrocode}
\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
{
\@@_scope_begin:
- \@@_matrix:n
+ \@@_literal:n
{
\fp_eval:n { round ( #2 , 5 ) } ~
- 0~0~
- \fp_eval:n { round ( #3 , 5 ) }
+ \fp_eval:n { round ( #3 , 5 ) } ~
+ scale
}
\hbox_overlap_right:n { \box_use:N #1 }
\@@_scope_end:
@@ -641,11 +618,10 @@
% \subsubsection{Color}
%
% \begin{variable}{\l_@@_color_current_tl}
-% The current color in driver-dependent format: pick up the package-mode
-% data if available.
+% The current color in driver-dependent format.
% \begin{macrocode}
\tl_new:N \l_@@_color_current_tl
-\tl_set:Nn \l_@@_color_current_tl { 0~g~0~G }
+\tl_set:Nn \l_@@_color_current_tl { gray~0 }
%<*package>
\AtBeginDocument
{
@@ -657,1154 +633,1248 @@
% \end{macrocode}
% \end{variable}
%
-% \begin{variable}{\l_@@_color_stack_int}
-% \pdfTeX{} and \LuaTeX{} have multiple stacks available, and to track
-% which one is in use a variable is required.
-% \begin{macrocode}
-\int_new:N \l_@@_color_stack_int
-% \end{macrocode}
-% \end{variable}
-%
% \begin{macro}[int]{\@@_color_ensure_current:}
% \begin{macro}[aux]{\@@_color_reset:}
-% There is a dedicated primitive/primitive interface for setting colors.
-% As with scoping, this approach is not suitable for cached operations.
+% Directly set the color using the specials: no optimisation here.
% \begin{macrocode}
-\cs_new_protected:Npx \@@_color_ensure_current:
- {
- \cs_if_exist:NTF \luatex_pdfextension:D
- { \luatex_pdfextension:D colorstack }
- { \pdftex_pdfcolorstack:D }
- \exp_not:N \l_@@_color_stack_int push
- { \exp_not:N \l_@@_color_current_tl }
- \group_insert_after:N \exp_not:N \@@_color_reset:
- }
-\cs_new_protected:Npx \@@_color_reset:
+\cs_new_protected:Npn \@@_color_ensure_current:
{
- \cs_if_exist:NTF \luatex_pdfextension:D
- { \luatex_pdfextension:D colorstack }
- { \pdftex_pdfcolorstack:D }
- \exp_not:N \l_@@_color_stack_int pop \scan_stop:
+ \tex_special:D { color~push~\l_@@_color_current_tl }
+ \group_insert_after:N \@@_color_reset:
}
+\cs_new_protected:Npn \@@_color_reset:
+ { \tex_special:D { color~pop } }
% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Images}
%
-% \begin{variable}{\l_@@_image_attr_tl}
-% In PDF mode, additional attributes of an image (such as page number) are
-% needed both to obtain the bounding box and when inserting the image: this
-% occurs as the image dictionary approach means they are read as part of
-% the bounding box operation. As such, it is easier to track additional
-% attributes using a dedicated |tl| rather than build up the same data
-% twice.
+% \begin{macro}[int]{\@@_image_getbb_eps:n}
+% Simply use the generic function.
% \begin{macrocode}
-\tl_new:N \l_@@_image_attr_tl
+\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
% \end{macrocode}
-% \end{variable}
+% \end{macro}
%
-% \begin{macro}[int]
-% {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n}
-% \begin{macro}[aux]
-% {\@@_image_getbb_auxi:n, \@@_image_getbb_auxii:n}
-% Getting the bounding box here requires us to box up the image and
-% measure it. To deal with the difference in feature support in bitmap
-% and vector images but keeping the common parts, there is a little work
-% to do in terms of auxiliaries. The key here is to notice that we need
-% two forms of the attributes: a \enquote{short} set to allow us to
-% track for caching, and the full form to pass to the primitive.
+% \begin{macro}[int]{\@@_image_include_eps:n}
+% The special syntax is relatively clear here: remember we need PostScript
+% sizes here.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
+\cs_new_protected:Npn \@@_image_include_eps:n #1
{
- \int_zero:N \l__image_page_int
- \tl_clear:N \l__image_pagebox_tl
- \tl_set:Nx \l_@@_image_attr_tl
- {
- \bool_if:NT \l__image_interpolate_bool
- { :I }
- }
- \tl_clear:N \l_@@_image_attr_tl
- \@@_image_getbb_auxi:n {#1}
+ \tex_special:D { PSfile = #1 }
}
-\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
-\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
+% \end{macrocode}
+% \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 off 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:
{
- \bool_set_false:N \l__image_interpolate_bool
- \tl_set:Nx \l_@@_image_attr_tl
- {
- : \l__image_pagebox_tl
- \int_compare:nNnT \l__image_page_int > 1
- { :P \int_use:N \l__image_page_int }
- }
- \@@_image_getbb_auxi:n {#1}
- }
-\cs_new_protected:Npn \@@_image_getbb_auxi:n #1
- {
- \dim_zero:N \l__image_llx_dim
- \dim_zero:N \l__image_lly_dim
- \dim_if_exist:cTF { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
- {
- \dim_set_eq:Nc \l__image_urx_dim
- { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
- \dim_set_eq:Nc \l__image_ury_dim
- { c__image_ #1 \l_@@_image_attr_tl _ury_dim }
- }
- { \@@_image_getbb_auxii:n {#1} }
- }
-% \begin{macrocode}
-% Measuring the image is done by boxing up: for PDF images we could
-% use |\pdftex_pdfximagebbox:D|, but if doesn't work for other types.
-% As the box will always start at $(0,0)$ there is no need to worry about
-% the lower-left position.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_getbb_auxii:n #1
- {
- \tex_immediate:D \pdftex_pdfximage:D
- \bool_if:NT \l__image_interpolate_bool
- { attr ~ { /Interpolate~true } }
- \int_compare:nNnT \l__image_page_int > 0
- { page ~ \int_use:N \l__image_page_int }
- \tl_if_empty:NF \l__image_pagebox_tl
- { \l__image_pagebox_tl }
- {#1}
- \hbox_set:Nn \l__image_tmp_box
- { \pdftex_pdfrefximage:D \pdftex_pdflastximage:D }
- \dim_set:Nn \l__image_urx_dim { \box_wd:N \l__image_tmp_box }
- \dim_set:Nn \l__image_ury_dim { \box_ht:N \l__image_tmp_box }
- \int_const:cn { c__image_ #1 \l_@@_image_attr_tl _int }
- { \tex_the:D \pdftex_pdflastximage:D }
- \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
- { \l__image_urx_dim }
- \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _ury_dim }
- { \l__image_ury_dim }
+ \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 }
}
-% \end{macrocode}
-% \end{macro}
-% \end{macro}
-%
-% \begin{macro}[int]
-% {\@@_image_include_jpg:n, \@@_image_include_pdf:n, \@@_image_include_png:n}
-% Images are already loaded for the measurement part of the code, so
-% inclusion is straight-forward, with only any attributes to worry about. The
-% latter carry through from determination of the bounding box.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_jpg:n #1
+\cs_new_protected:Npn \@@_draw_end:
{
- \pdftex_pdfrefximage:D
- \int_use:c { c__image_ #1 \l_@@_image_attr_tl _int }
+ \tex_special:D { ps::~@endspecial }
+ \tex_special:D { ps::~restore }
+ \tex_special:D { ps::[end] }
}
-\cs_new_eq:NN \@@_image_include_pdf:n \@@_image_include_jpg:n
-\cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macrocode}
-%</pdfmode>
-% \end{macrocode}
-%
-% \subsection{\texttt{dvipdfmx} driver}
-%
-% \begin{macrocode}
-%<*dvipdfmx|xdvipdfmx>
-% \end{macrocode}
-%
-% The \texttt{dvipdfmx} shares code with the PDF mode one (using the common
-% section to this file) but also with \texttt{xdvipdfmx}. The latter is close
-% to identical to \texttt{dvipdfmx} and so all of the code here is extracted
-% for both drivers, with some \texttt{clean up} for \texttt{xdvipdfmx} as
-% required.
-%
-% \subsubsection{Basics}
-%
-% \begin{macro}[int]{\@@_literal:n}
-% Equivalent to \texttt{pdf:content} but favored as the link to
-% the \pdfTeX{} primitive approach is clearer. Some higher-level operations
-% use |\tex_special:D| directly: see the later comments on where this is
-% useful.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_literal:n #1
- { \tex_special:D { pdf:literal~ #1 } }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
-% Scoping is done using the driver-specific specials.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_scope_begin:
- { \tex_special:D { x:gsave } }
-\cs_new_protected:Npn \@@_scope_end:
- { \tex_special:D { x:grestore } }
+% \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}
%
-% \subsubsection{Box operations}
-%
-% \begin{macro}{\@@_box_use_clip:N}
-% The code here is idential to that for \texttt{pdfmode}: unlike rotation and
-% scaling, there is no higher-level support in the driver for clipping.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_clip:N #1
+% \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
{
- \@@_scope_begin:
- \@@_literal:n
- {
- 0~
- \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~
- \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
- \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~
- re~W~n
- }
- \hbox_overlap_right:n { \box_use:N #1 }
- \@@_scope_end:
- \skip_horizontal:n { \box_wd:N #1 }
+ \@@_draw_literal:x
+ { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ moveto }
}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}[int]{\@@_box_use_rotate:Nn}
-% Rotating in \texttt{(x)}dvipdmfx can be implemented using either PDF or
-% driver-specific code. The former approach however is not \enquote{aware}
-% of the content of boxes: this means that any links embded will not be
-% adjusted by the rotation. As such, the driver-native approach is prefered:
-% the code therefore is similar (though not identical) to the \texttt{dvips}
-% version (notice the rotation angle here is positive). As for
-% \texttt{dvips}, zero rotation is written as |0| not |-0|.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
+\cs_new_protected:Npn \@@_draw_lineto:nn #1#2
{
- \@@_scope_begin:
- \tex_special:D
- {
- x:rotate~
- \fp_compare:nNnTF {#2} = \c_zero_fp
- { 0 }
- { \fp_eval:n { round ( #2 , 5 ) } }
+ \@@_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~closepath
}
- \box_use:N #1
- \@@_scope_end:
}
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_box_use_scale:Nnn}
-% Much the same idea for scaling: use the higher-level driver operation to allow
-% for box content.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
+\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6
{
- \@@_scope_begin:
- \tex_special:D
+ \@@_draw_literal:x
{
- x:scale~
- \fp_eval:n { round ( #2 , 5 ) } ~
- \fp_eval:n { round ( #3 , 5 ) }
+ \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
}
- \hbox_overlap_right:n { \box_use:N #1 }
- \@@_scope_end:
- }
+ }
% \end{macrocode}
% \end{macro}
+% \end{macro}
+% \end{macro}
%
-% \subsubsection{Color}
-%
-% \begin{variable}{\l_@@_color_current_tl}
-% The current color in driver-dependent format.
-% \begin{macrocode}
-\tl_new:N \l_@@_color_current_tl
-\tl_set:Nn \l_@@_color_current_tl { [ 0 ] }
-%<*package>
-\AtBeginDocument
- {
- \@ifpackageloaded { color }
- { \tl_set:Nn \l_@@_color_current_tl { \current at color } }
- { }
- }
-%</package>
+% \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}
-%
-% \begin{macro}[int]{\@@_color_ensure_current:}
-% \begin{macro}[aux]{\@@_color_reset:}
-% Directly set the color using the specials with optimisation support.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_color_ensure_current:
- {
- \tex_special:D { pdf:bcolor~\l_@@_color_current_tl }
- \group_insert_after:N \@@_color_reset:
- }
-\cs_new_protected:Npn \@@_color_reset:
- { \tex_special:D { pdf:ecolor } }
-% \end{macrocode}
-% \end{macro}
% \end{macro}
%
-% \subsection{Images}
-%
% \begin{macro}[int]
% {
-% \@@_image_getbb_eps:n, \@@_image_getbb_jpg:n,
-% \@@_image_getbb_pdf:n, \@@_image_getbb_png:n
+% \@@_draw_closepath: ,
+% \@@_draw_stroke: ,
+% \@@_draw_closestroke: ,
+% \@@_draw_fill: ,
+% \@@_draw_fillstroke: ,
+% \@@_draw_clip: ,
+% \@@_draw_discardpath:
% }
-% Simply use the generic functions: only for \texttt{dvipdfmx} in the
-% extraction cases.
-% \begin{macrocode}
-\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
-%<*dvipdfmx>
-\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
- {
- \int_zero:N \l__image_page_int
- \tl_clear:N \l__image_pagebox_tl
- \__image_extract_bb:n {#1}
- }
-\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
-\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
+% \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:
{
- \bool_set_false:N \l__image_interpolate_tl
- \__image_extract_bb:n {#1}
+ \@@_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
}
-%</dvipdfmx>
-% \end{macrocode}
-% \end{macro}
-%
-% \begin{variable}[aux]{\g_@@_image_int}
-% Used to track the object number associated with each image.
-% \begin{macrocode}
-\int_new:N \g_@@_image_int
-% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[int]
-% {
-% \@@_image_include_eps:n, \@@_image_include_jpg:n,
-% \@@_image_include_pdf:n, \@@_image_include_png:n
-% }
-% \begin{macro}[aux]{\@@_image_include_auxi:nn}
-% \begin{macro}[aux]{\@@_image_include_auxii:nnn, \@@_image_include_auxii:xnn}
-% \begin{macro}[aux]{\@@_image_include_auxiii:nn}
-% The special syntax depends on the file type. There is a difference in
-% how PDF images are best handled between |dvipdfmx| and |xdvipdfmx|: for
-% the latter it is better to use the primitive route. The relevant code for
-% that is included later in this file.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_eps:n #1
+\cs_new_protected:Npn \@@_draw_closestroke:
{
- \tex_special:D { PSfile = #1 }
+ \@@_draw_closepath:
+ \@@_draw_stroke:
}
-\cs_new_protected:Npn \@@_image_include_jpg:n #1
- { \@@_image_include_auxi:nn {#1} { image } }
-\cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n
-%<*dvipdfmx>
-\cs_new_protected:Npn \@@_image_include_pdf:n #1
- { \@@_image_include_auxi:nn {#1} { epdf } }
-%</dvipdfmx>
-% \end{macrocode}
-% Image inclusion is set up to use the fact that each image is stored in
-% the PDF as an XObject. This means that we can include repeated images
-% only once and refer to them. To allow that, track the nature of each
-% image: much the same as for the direct PDF mode case.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_auxi:nn #1#2
+\cs_new_protected:Npn \@@_draw_fill:
{
- \@@_image_include_auxii:xnn
+ \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
+ \@@_draw_literal:x
{
- \tl_if_empty:NF \l__image_pagebox_tl
- { : \l__image_pagebox_tl }
- \int_compare:nNnT \l__image_page_int > 1
- { :P \int_use:N \l__image_page_int }
- \bool_if:NT \l__image_interpolate_bool
- { :I }
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ fill
}
- {#1} {#2}
+ \@@_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 \@@_image_include_auxii:nnn #1#2#3
+\cs_new_protected:Npn \@@_draw_fillstroke:
{
- \int_if_exist:cTF { c__image_ #2#1 _int }
+ \@@_draw_literal:n { currentdict~/l3fc~known~{gsave~l3fc}~if }
+ \@@_draw_literal:x
{
- \tex_special:D
- { pdf:usexobj~@image \int_use:c { c__image_ #2#1 _int } }
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ fill
}
- { \@@_image_include_auxiii:nn {#2} {#1} {#3} }
+ \@@_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_generate_variant:Nn \@@_image_include_auxii:nnn { x }
-% \end{macrocode}
-% Inclusion using the specials is relatively straight-forward, but there
-% is one wrinkle. To get the |pagebox| correct for PDF images in all cases,
-% it is necessary to provide both that information and the |bbox| argument:
-% odd things happen otherwise!
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_auxiii:nnn #1#2#3
+\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:
{
- \int_gincr:N \g_@@_image_int
- \int_const:cn { c__image_ #1#2 _int } { \g_@@_image_int }
- \tex_special:D
+ \bool_if:NT \g_@@_draw_clip_bool
{
- pdf:#3~
- @image \int_use:c { c__image_ #1#2 _int }
- \int_compare:nNnT \l__image_page_int > 1
- { page ~ \int_use:N \l__image_page_int \c_space_tl }
- \tl_if_empty:NF \l__image_pagebox_tl
+ \@@_draw_literal:x
{
- pagebox ~ \l__image_pagebox_tl \c_space_tl
- bbox ~
- \dim_to_decimal_in_bp:n \l__image_llx_dim \c_space_tl
- \dim_to_decimal_in_bp:n \l__image_lly_dim \c_space_tl
- \dim_to_decimal_in_bp:n \l__image_urx_dim \c_space_tl
- \dim_to_decimal_in_bp:n \l__image_ury_dim \c_space_tl
+ \bool_if:NT \g_@@_draw_eor_bool { eo }
+ clip
}
- (#1)
- \bool_if:NT \l__image_interpolate_bool
- { <</Interpolate~true>> }
}
+ \@@_draw_literal:n { newpath }
+ \bool_gset_false:N \g_@@_draw_clip_bool
}
% \end{macrocode}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+% \end{variable}
% \end{macro}
%
-% \begin{macrocode}
-%</dvipdfmx|xdvipdfmx>
-% \end{macrocode}
-%
-% \subsection{\texttt{xdvipdfmx} driver}
-%
-% \begin{macrocode}
-%<*xdvipdfmx>
-% \end{macrocode}
-%
-% \subsubsection{Color}
-%
-% \begin{macro}[int]{\@@_color_ensure_current:}
-% \begin{macro}[aux]{\@@_color_reset:}
-% Older \LaTeXe{} drivers uses \texttt{dvips}-like specials so there has to
-% be a change of set up if \pkg{color} is loaded and if the current color
-% doesn't match the pattern expected for |dvipdfmx|.
-% \begin{macrocode}
-%<*package>
-\AtBeginDocument
+% \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
{
- \@ifpackageloaded { color }
+ \@@_draw_literal:x
{
- \cs_set_protected:Npn \@@_tmp:w #1 [ #2 ] #3 \q_stop
- {
- \tl_if_empty:nT {#2}
- {
- \cs_set_protected:Npn \@@_color_ensure_current:
- {
- \tex_special:D { color~push~\l_@@_color_current_tl }
- \group_insert_after:N \@@_color_reset:
- }
- \cs_set_protected:Npn \@@_color_reset:
- { \tex_special:D { color~pop } }
- }
- }
- \exp_after:wN \@@_tmp:w \current at color [ ] \q_stop
+ [ ~
+ \clist_map_function:nN {#1} \@@_draw_dash:n
+ ] ~
+ \dim_to_decimal_in_bp:n {#2} ~ setdash
}
- { }
}
-%</package>
+\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}
%
-% \subsection{Images}
-%
+% \begin{macro}[aux]{\_@@_draw_color_reset:}
% \begin{macro}[int]
-% {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n}
-% \begin{macro}[aux]{\@@_image_getbb_auxi:nN}
-% \begin{macro}[aux]{\@@_image_getbb_auxii:nnN, \@@_image_getbb_auxii:VnN}
-% \begin{macro}[aux]{\@@_image_getbb_auxiii:nNnn}
-% \begin{macro}[aux]{\@@_image_getbb_auxiv:nnNnn, \@@_image_getbb_auxiv:VnNnn}
-% \begin{macro}[aux]{\@@_image_getbb_auxv:nNnn, \@@_image_getbb_auxv:nNnn}
-% \begin{macro}[aux, EXP]{\@@_image_getbb_pagebox:w}
-% For \texttt{xdvipdfmx}, there are two primitives that allow us to obtain
-% the bounding box without needing \texttt{extractbb}. The only complexity
-% is passing the various minor variations to a common core process. The
-% \XeTeX{} primitive omits the text |box| from the page box specification,
-% so there is also some \enquote{trimming} to do here.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
+% {
+% \@@_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:
{
- \int_zero:N \l__image_page_int
- \@@_image_getbb_auxi:nN {#1} \xetex_picfile:D
+ \@@_draw_literal:n { currentdic~/l3fc~known~{ /l3fc~ { } ~def }~if }
+ \@@_draw_literal:n { currentdic~/l3sc~known~{ /l3sc~ { } ~def }~if }
}
-\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
-\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
- { \@@_image_getbb_auxi:nN {#1} \xetex_pdffile:D }
-\cs_new_protected:Npn \@@_image_getbb_auxi:nN #1#2
+\cs_new_protected:Npn \@@_draw_color_cmyk:nnnn #1#2#3#4
{
- \int_compare:nNnTF \l__image_page_int > 1
- { \@@_image_getbb_auxii:VnN \l__image_page_int {#1} #2 }
- { \@@_image_getbb_auxiii:nNnn {#1} #2 }
+ \@@_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 \@@_image_getbb_auxii:nnN #1#2#3
- { \@@_image_getbb_aux:nNnn {#2} #3 { :P #1 } { page #1 } }
-\cs_generate_variant:Nn \@@_image_getbb_auxii:nnN { V }
-\cs_new_protected:Npn \@@_image_getbb_auxiii:nNnn #1#2#3#4
+\cs_new_protected:Npn \@@_draw_color_cmyk_fill:nnnn #1#2#3#4
{
- \tl_if_empty:NTF \l__image_pagebox_tl
- { \@@_image_getbb_auxiv:VnNnn \l__image_pagebox_tl }
- { \@@_image_getbb_auxv: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 \@@_image_getbb_auxiv:nnNnn #1#2#3#4#5
+\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
{
- \use:x
+ \__driver_draw_literal:x
{
- \@@_image_getbb_auxv:nNnn {#2} #3 { : #1 #4 }
- { #5 ~ \@@_image_getbb_pagebox:w #1 }
+ /l3sc ~
+ {
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+ \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+ setcmykcolor
+ } ~
+ def
}
}
-\cs_generate_variant:Nn \@@_image_getbb_auxiv:nnNnn { V }
-\cs_new_protected:Npn \@@_image_getbb_auxv:nNnn #1#2#3#4
+\cs_new_protected:Npn \@@_draw_color_gray:n #1
{
- \dim_zero:N \l__image_llx_dim
- \dim_zero:N \l__image_lly_dim
- \dim_if_exist:cTF { c__image_ #1#3 _urx_dim }
+ \@@_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
{
- \dim_set_eq:Nc \l__image_urx_dim { c__image_ #1#3 _urx_dim }
- \dim_set_eq:Nc \l__image_ury_dim { c__image_ #1#3 _ury_dim }
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
+ setrgbcolor
}
- { \@@_image_getbb_auxvi:nNnn {#1} #2 {#3} {#4} }
+ \@@_draw_color_reset:
}
-\cs_new_protected:Npn \@@_image_getbb_auxvi:nNnn #1#2#3#4
+\cs_new_protected:Npn \@@_draw_color_rgb_fill:nnn #1#2#3
{
- \hbox_set:Nn \l__image_tmp_box { #2 #1 ~ #4 }
- \dim_set:Nn \l__image_utx_dim { \box_wd:N \l__image_tmp_box }
- \dim_set:Nn \l__image_ury_dim { \box_ht:N \l__image_tmp_box }
- \dim_const:cn { c__image_ #1#3 _urx_dim }
- { \l__image_urx_dim }
- \dim_const:cn { c__image_ #1#3 _ury_dim }
- { \l__image_ury_dim }
+ \@@_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
+ }
}
-\cs_new:Npn \@@_image_getbb_pagebox:w #1 box {#1}
% \end{macrocode}
% \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
+% 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]{\@@_image_include_pdf:n}
-% For PDF images, properly supporting the |pagebox| concept in \XeTeX{}
-% is best done using the |\xetex_pdffile:D| primitive. The syntax here
-% is the same as for the image measurement part, although we know at this
-% stage that there must be some valid setting for \cs{l__image_pagebox_tl}.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_pdf:n #1
+% \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
{
- \xetex_pdffile:D "#1" ~
- \int_compare:nNnT \l__image_page_int > 0
- { page~ \int_use:N \l__image_page_int }
- \@@_image_getbb_auxiv:VnNnn \l__image_pagebox_tl
+ \@@_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}
-%</xdvipdfmx>
+%</dvips>
% \end{macrocode}
%
-% \subsection{Drawing commands: \texttt{pdfmode} and \texttt{(x)dvipdfmx}}
-%
-% Both \texttt{pdfmode} and \texttt{(x)dvipdfmx} directly produce PDF output
-% and understand a shared set of specials for drawing commands.
+% \subsection{\texttt{pdfmode} driver}
%
% \begin{macrocode}
-%<*dvipdfmx|pdfmode|xdvipdfmx>
+%<*pdfmode>
% \end{macrocode}
%
-% \subsection{Drawing}
+% The direct PDF driver covers both \pdfTeX{} and \LuaTeX{}. The latter
+% renames/restructures the driver primitives but this can be handled
+% at one level of abstraction. As such, we avoid using two separate drivers
+% for this material at the cost of some \texttt{x}-type definitions to get
+% everything expanded up-front.
%
-% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x}
-% Pass data through using a dedicated interface.
-% \begin{macrocode}
-\cs_new_eq:NN \@@_draw_literal:n \@@_literal:n
-\cs_generate_variant:Nn \@@_draw_literal:n { x }
+% \subsubsection{Basics}
+%
+% \begin{macro}[int]{\@@_literal:n}
+% This is equivalent to \verb|\special{pdf:}| but the engine can
+% track it. Without the \texttt{direct} keyword everything is kept in
+% sync: the transformation matrix is set to the current point automatically.
+% Note that this is still inside the text (\texttt{BT} \dots \texttt{ET}
+% block).
+% \begin{macrocode}
+\cs_new_protected:Npx \@@_literal:n #1
+ {
+ \cs_if_exist:NTF \luatex_pdfextension:D
+ { \luatex_pdfextension:D literal }
+ { \pdftex_pdfliteral:D }
+ {#1}
+ }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\@@_draw_begin:, \@@_draw_end:}
-% No special requirements here, so simply set up a drawing scope.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_begin:
- { \@@_draw_scope_begin: }
-\cs_new_protected:Npn \@@_draw_end:
- { \@@_draw_scope_end: }
+% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
+% Higher-level interfaces for saving and restoring the graphic state.
+% \begin{macrocode}
+\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:Npx \@@_scope_end:
+ {
+ \cs_if_exist:NTF \luatex_pdfextension:D
+ { \luatex_pdfextension:D restore \scan_stop: }
+ { \pdftex_pdfrestore:D }
+ }
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\@@_draw_scope_begin:, \@@_draw_scope_end:}
-% 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:Npn \@@_draw_scope_begin:
- { \@@_draw_literal:n { q } }
-\cs_new_protected:Npn \@@_draw_scope_end:
- { \@@_draw_literal:n { Q } }
+% \begin{macro}[int]{\@@_matrix:n}
+% Here the appropriate function is set up to insert an affine matrix
+% into the PDF. With \pdfTeX{} and \LuaTeX{} in direct PDF output mode there
+% is a primitive for this, which only needs the rotation/scaling/skew part.
+% \begin{macrocode}
+\cs_new_protected:Npx \@@_matrix:n #1
+ {
+ \cs_if_exist:NTF \luatex_pdfextension:D
+ { \luatex_pdfextension:D setmatrix }
+ { \pdftex_pdfsetmatrix:D }
+ {#1}
+ }
% \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
-% forced to literals before any possible caching.
-% \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} ~ m }
- }
-\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} ~ l }
- }
-\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} ~
- c
- }
- }
-\cs_new_protected:Npn \@@_draw_rectangle:nnnn #1#2#3#4
+% \subsubsection{Box operations}
+%
+% \begin{macro}{\@@_box_use_clip:N}
+% The general method is to save the current location, define a clipping path
+% equivalent to the bounding box, then insert the content at the current
+% position and in a zero width box. The \enquote{real} width is then made up
+% using a horizontal skip before tidying up. There are other approaches that
+% can be taken (for example using XForm objects), but the logic here shares
+% as much code as possible and uses the same conversions (and so same
+% rounding errors) in all cases.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_clip:N #1
{
- \@@_draw_literal:x
+ \@@_scope_begin:
+ \@@_literal:n
{
- \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
+ 0~
+ \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~
+ \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
+ \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~
+ re~W~n
}
+ \hbox_overlap_right:n { \box_use:N #1 }
+ \@@_scope_end:
+ \skip_horizontal:n { \box_wd:N #1 }
}
% \end{macrocode}
% \end{macro}
-% \end{macro}
-% \end{macro}
%
-% \begin{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:}
-% \begin{variable}[int]{\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
+% \begin{macro}[int]{\@@_box_use_rotate:Nn}
+% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
+% Rotations are set using an affine transformation matrix which therefore
+% requires sine/cosine values not the angle itself. We store the rounded
+% values to avoid rounding twice. There are also a couple of comparisons to
+% ensure that |-0| is not written to the output, as this avoids any issues
+% with problematic display programs. Note that numbers are compared to~$0$
+% after rounding.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
+ {
+ \@@_scope_begin:
+ \box_set_wd:Nn #1 \c_zero_dim
+ \fp_set:Nn \l_@@_cos_fp { round ( cosd ( #2 ) , 5 ) }
+ \fp_compare:nNnT \l_@@_cos_fp = \c_zero_fp
+ { \fp_zero:N \l_@@_cos_fp }
+ \fp_set:Nn \l_@@_sin_fp { round ( sind ( #2 ) , 5 ) }
+ \@@_matrix:n
+ {
+ \fp_use:N \l_@@_cos_fp \c_space_tl
+ \fp_compare:nNnTF \l_@@_sin_fp = \c_zero_fp
+ { 0~0 }
+ {
+ \fp_use:N \l_@@_sin_fp
+ \c_space_tl
+ \fp_eval:n { -\l_@@_sin_fp }
+ }
+ \c_space_tl
+ \fp_use:N \l_@@_cos_fp
+ }
+ \box_use:N #1
+ \@@_scope_end:
+ }
+\fp_new:N \l_@@_cos_fp
+\fp_new:N \l_@@_sin_fp
% \end{macrocode}
% \end{variable}
% \end{macro}
%
-% \begin{macro}[int]
-% {
-% \@@_draw_closepath: ,
-% \@@_draw_stroke: ,
-% \@@_draw_closestroke: ,
-% \@@_draw_fill: ,
-% \@@_draw_fillstroke: ,
-% \@@_draw_clip: ,
-% \@@_draw_discardpath:
-% }
-% Converting paths to output is again a case of mapping directly to
-% PDF operations.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_closepath:
- { \@@_draw_literal:n { h } }
-\cs_new_protected:Npn \@@_draw_stroke:
- { \@@_draw_literal:n { S } }
-\cs_new_protected:Npn \@@_draw_closestroke:
- { \@@_draw_literal:n { s } }
-\cs_new_protected:Npn \@@_draw_fill:
- {
- \@@_draw_literal:x
- { f \bool_if:NT \g_@@_draw_eor_bool * }
- }
-\cs_new_protected:Npn \@@_draw_fillstroke:
+% \begin{macro}{\@@_box_use_scale:Nnn}
+% The same idea as for rotation but without the complexity of signs and
+% cosines.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
{
- \@@_draw_literal:x
- { B \bool_if:NT \g_@@_draw_eor_bool * }
+ \@@_scope_begin:
+ \@@_matrix:n
+ {
+ \fp_eval:n { round ( #2 , 5 ) } ~
+ 0~0~
+ \fp_eval:n { round ( #3 , 5 ) }
+ }
+ \hbox_overlap_right:n { \box_use:N #1 }
+ \@@_scope_end:
}
-\cs_new_protected:Npn \@@_draw_clip:
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Color}
+%
+% \begin{variable}{\l_@@_color_current_tl}
+% The current color in driver-dependent format: pick up the package-mode
+% data if available.
+% \begin{macrocode}
+\tl_new:N \l_@@_color_current_tl
+\tl_set:Nn \l_@@_color_current_tl { 0~g~0~G }
+%<*package>
+\AtBeginDocument
{
- \@@_draw_literal:x
- { W \bool_if:NT \g_@@_draw_eor_bool * }
+ \@ifpackageloaded { color }
+ { \tl_set:Nn \l_@@_color_current_tl { \current at color } }
+ { }
}
-\cs_new_protected:Npn \@@_draw_discardpath:
- { \@@_draw_literal:n { n } }
+%</package>
% \end{macrocode}
-% \end{macro}
+% \end{variable}
%
-% \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
-% PDF operations.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_dash:nn #1#2
+% \begin{variable}{\l_@@_color_stack_int}
+% \pdfTeX{} and \LuaTeX{} have multiple stacks available, and to track
+% which one is in use a variable is required.
+% \begin{macrocode}
+\int_new:N \l_@@_color_stack_int
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}[int]{\@@_color_ensure_current:}
+% \begin{macro}[aux]{\@@_color_reset:}
+% 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:Npx \@@_color_ensure_current:
{
- \@@_draw_literal:x
- {
- [ ~
- \clist_map_function:nN {#1} \@@_draw_dash:n
- ] ~
- \dim_to_decimal_in_bp:n {#2} ~ d
- }
+ \cs_if_exist:NTF \luatex_pdfextension:D
+ { \luatex_pdfextension:D colorstack }
+ { \pdftex_pdfcolorstack:D }
+ \exp_not:N \l_@@_color_stack_int push
+ { \exp_not:N \l_@@_color_current_tl }
+ \group_insert_after:N \exp_not:N \@@_color_reset:
}
-\cs_new:Npn \@@_draw_dash:n #1
- { \dim_to_decimal_in_bp:n {#1} ~ }
-\cs_new_protected:Npn \@@_draw_linewidth:n #1
+\cs_new_protected:Npx \@@_color_reset:
{
- \@@_draw_literal:x
- { \dim_to_decimal_in_bp:n {#1} ~ w }
+ \cs_if_exist:NTF \luatex_pdfextension:D
+ { \luatex_pdfextension:D colorstack }
+ { \pdftex_pdfcolorstack:D }
+ \exp_not:N \l_@@_color_stack_int pop \scan_stop:
}
-\cs_new_protected:Npn \@@_draw_miterlimit:n #1
- { \@@_draw_literal:x { \fp_eval:n {#1} ~ M } }
-\cs_new_protected:Npn \@@_draw_cap_butt:
- { \@@_draw_literal:n { 0 ~ J } }
-\cs_new_protected:Npn \@@_draw_cap_round:
- { \@@_draw_literal:n { 1 ~ J } }
-\cs_new_protected:Npn \@@_draw_cap_rectangle:
- { \@@_draw_literal:n { 2 ~ J } }
-\cs_new_protected:Npn \@@_draw_join_miter:
- { \@@_draw_literal:n { 0 ~ j } }
-\cs_new_protected:Npn \@@_draw_join_round:
- { \@@_draw_literal:n { 1 ~ j } }
-\cs_new_protected:Npn \@@_draw_join_bevel:
- { \@@_draw_literal:n { 2 ~ j } }
% \end{macrocode}
% \end{macro}
% \end{macro}
-% \end{macro}
-% \end{macro}
-% \end{macro}
+%
+% \subsection{Images}
+%
+% \begin{variable}{\l_@@_image_attr_tl}
+% In PDF mode, additional attributes of an image (such as page number) are
+% needed both to obtain the bounding box and when inserting the image: this
+% occurs as the image dictionary approach means they are read as part of
+% the bounding box operation. As such, it is easier to track additional
+% attributes using a dedicated |tl| rather than build up the same data
+% twice.
+% \begin{macrocode}
+\tl_new:N \l_@@_image_attr_tl
+% \end{macrocode}
+% \end{variable}
%
% \begin{macro}[int]
-% {
-% \@@_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: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: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
+% {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n}
+% \begin{macro}[aux]
+% {\@@_image_getbb_auxi:n, \@@_image_getbb_auxii:n}
+% Getting the bounding box here requires us to box up the image and
+% measure it. To deal with the difference in feature support in bitmap
+% and vector images but keeping the common parts, there is a little work
+% to do in terms of auxiliaries. The key here is to notice that we need
+% two forms of the attributes: a \enquote{short} set to allow us to
+% track for caching, and the full form to pass to the primitive.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
{
- \use:x
+ \int_zero:N \l__image_page_int
+ \tl_clear:N \l__image_pagebox_tl
+ \tl_set:Nx \l_@@_image_attr_tl
{
- \@@_draw_color_cmyk_aux:nnnn
- { \fp_eval:n {#1} }
- { \fp_eval:n {#2} }
- { \fp_eval:n {#3} }
- { \fp_eval:n {#4} }
+ \bool_if:NT \l__image_interpolate_bool
+ { :I }
}
+ \tl_clear:N \l_@@_image_attr_tl
+ \@@_image_getbb_auxi:n {#1}
}
-\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
+\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
+\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
{
- \@@_draw_literal:x
+ \bool_set_false:N \l__image_interpolate_bool
+ \tl_set:Nx \l_@@_image_attr_tl
{
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- k
+ : \l__image_pagebox_tl
+ \int_compare:nNnT \l__image_page_int > 1
+ { :P \int_use:N \l__image_page_int }
}
+ \@@_image_getbb_auxi:n {#1}
}
-\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
+\cs_new_protected:Npn \@@_image_getbb_auxi:n #1
{
- \@@_draw_literal:x
+ \dim_zero:N \l__image_llx_dim
+ \dim_zero:N \l__image_lly_dim
+ \dim_if_exist:cTF { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
{
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- K
+ \dim_set_eq:Nc \l__image_urx_dim
+ { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
+ \dim_set_eq:Nc \l__image_ury_dim
+ { c__image_ #1 \l_@@_image_attr_tl _ury_dim }
}
+ { \@@_image_getbb_auxii:n {#1} }
}
-\cs_new_protected:Npn \@@_draw_color_gray:n #1
+% \begin{macrocode}
+% Measuring the image is done by boxing up: for PDF images we could
+% use |\pdftex_pdfximagebbox:D|, but if doesn't work for other types.
+% As the box will always start at $(0,0)$ there is no need to worry about
+% the lower-left position.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_image_getbb_auxii:n #1
{
- \use:x
- { \@@_draw_color_gray_aux:n { \fp_eval:n {#1} } }
+ \tex_immediate:D \pdftex_pdfximage:D
+ \bool_if:NT \l__image_interpolate_bool
+ { attr ~ { /Interpolate~true } }
+ \int_compare:nNnT \l__image_page_int > 0
+ { page ~ \int_use:N \l__image_page_int }
+ \tl_if_empty:NF \l__image_pagebox_tl
+ { \l__image_pagebox_tl }
+ {#1}
+ \hbox_set:Nn \l__image_tmp_box
+ { \pdftex_pdfrefximage:D \pdftex_pdflastximage:D }
+ \dim_set:Nn \l__image_urx_dim { \box_wd:N \l__image_tmp_box }
+ \dim_set:Nn \l__image_ury_dim { \box_ht:N \l__image_tmp_box }
+ \int_const:cn { c__image_ #1 \l_@@_image_attr_tl _int }
+ { \tex_the:D \pdftex_pdflastximage:D }
+ \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _urx_dim }
+ { \l__image_urx_dim }
+ \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _ury_dim }
+ { \l__image_ury_dim }
}
-\cs_new_protected:Npn \@@_draw_color_gray_aux:n #1
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[int]
+% {\@@_image_include_jpg:n, \@@_image_include_pdf:n, \@@_image_include_png:n}
+% Images are already loaded for the measurement part of the code, so
+% inclusion is straight-forward, with only any attributes to worry about. The
+% latter carry through from determination of the bounding box.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_image_include_jpg:n #1
{
- \@@_draw_literal:n { #1 ~ g ~ #1 ~ G }
+ \pdftex_pdfrefximage:D
+ \int_use:c { c__image_ #1 \l_@@_image_attr_tl _int }
}
-\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
+\cs_new_eq:NN \@@_image_include_pdf:n \@@_image_include_jpg:n
+\cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</pdfmode>
+% \end{macrocode}
+%
+% \subsection{\texttt{dvipdfmx} driver}
+%
+% \begin{macrocode}
+%<*dvipdfmx|xdvipdfmx>
+% \end{macrocode}
+%
+% The \texttt{dvipdfmx} shares code with the PDF mode one (using the common
+% section to this file) but also with \texttt{xdvipdfmx}. The latter is close
+% to identical to \texttt{dvipdfmx} and so all of the code here is extracted
+% for both drivers, with some \texttt{clean up} for \texttt{xdvipdfmx} as
+% required.
+%
+% \subsubsection{Basics}
+%
+% \begin{macro}[int]{\@@_literal:n}
+% Equivalent to \texttt{pdf:content} but favored as the link to
+% the \pdfTeX{} primitive approach is clearer. Some higher-level operations
+% use |\tex_special:D| directly: see the later comments on where this is
+% useful.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_literal:n #1
+ { \tex_special:D { pdf:literal~ #1 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}[int]{\@@_scope_begin:, \@@_scope_end:}
+% Scoping is done using the driver-specific specials.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_scope_begin:
+ { \tex_special:D { x:gsave } }
+\cs_new_protected:Npn \@@_scope_end:
+ { \tex_special:D { x:grestore } }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsubsection{Box operations}
+%
+% \begin{macro}{\@@_box_use_clip:N}
+% The code here is idential to that for \texttt{pdfmode}: unlike rotation and
+% scaling, there is no higher-level support in the driver for clipping.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_clip:N #1
{
- \use:x
+ \@@_scope_begin:
+ \@@_literal:n
{
- \@@_draw_color_rgb_aux:nnn
- { \fp_eval:n {#1} }
- { \fp_eval:n {#2} }
- { \fp_eval:n {#3} }
+ 0~
+ \dim_to_decimal_in_bp:n { -\box_dp:N #1 } ~
+ \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
+ \dim_to_decimal_in_bp:n { \box_ht:N #1 + \box_dp:N #1 } ~
+ re~W~n
}
- }
-\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
- { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ rg }
- }
-\cs_new_protected:Npn \@@_draw_color_rgb_stroke:nnn #1#2#3
- {
- \@@_draw_literal:x
- { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ RG }
+ \hbox_overlap_right:n { \box_use:N #1 }
+ \@@_scope_end:
+ \skip_horizontal:n { \box_wd:N #1 }
}
% \end{macrocode}
% \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
-% 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
+% \begin{macro}[int]{\@@_box_use_rotate:Nn}
+% Rotating in \texttt{(x)}dvipdmfx can be implemented using either PDF or
+% driver-specific code. The former approach however is not \enquote{aware}
+% of the content of boxes: this means that any links embded will not be
+% adjusted by the rotation. As such, the driver-native approach is prefered:
+% the code therefore is similar (though not identical) to the \texttt{dvips}
+% version (notice the rotation angle here is positive). As for
+% \texttt{dvips}, zero rotation is written as |0| not |-0|.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
{
- \@@_draw_literal:x
+ \@@_scope_begin:
+ \tex_special:D
{
- \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} ~
- cm
+ x:rotate~
+ \fp_compare:nNnTF {#2} = \c_zero_fp
+ { 0 }
+ { \fp_eval:n { round ( #2 , 5 ) } }
}
+ \box_use:N #1
+ \@@_scope_end:
}
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}[int]{\@@_draw_hbox:Nnnnnnn}
-% \begin{variable}[aux]{\l_@@_tmp_box}
-% Inserting a \TeX{} box transformed to the requested position and using
-% the current matrix is done using a mixture of \TeX{} and low-level
-% manipulation. The offset can be handled by \TeX{}, so only any rotation/^^A
-% skew/scaling component needs to be done using the matrix operation. As this
-% operation can never be cached, the scope is set directly not using the
-% \texttt{draw} version.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_hbox:Nnnnnnn #1#2#3#4#5#6#7
+% \begin{macro}{\@@_box_use_scale:Nnn}
+% Much the same idea for scaling: use the higher-level driver operation to allow
+% for box content.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
{
- \hbox_set:Nn \l_@@_tmp_box
+ \@@_scope_begin:
+ \tex_special:D
{
- \tex_kern:D \__dim_eval:w #6 \__dim_eval_end:
- \@@_scope_begin:
- \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5}
- { 0pt } { 0pt }
- \box_move_up:nn {#7} { \box_use:N #1 }
- \@@_scope_end:
+ x:scale~
+ \fp_eval:n { round ( #2 , 5 ) } ~
+ \fp_eval:n { round ( #3 , 5 ) }
}
- \box_set_wd:Nn \l_@@_tmp_box { 0pt }
- \box_set_ht:Nn \l_@@_tmp_box { 0pt }
- \box_set_dp:Nn \l_@@_tmp_box { 0pt }
- \box_use:N \l_@@_tmp_box
+ \hbox_overlap_right:n { \box_use:N #1 }
+ \@@_scope_end:
}
-\box_new:N \l_@@_tmp_box
% \end{macrocode}
-% \end{variable}
% \end{macro}
%
+% \subsubsection{Color}
+%
+% \begin{variable}{\l_@@_color_current_tl}
+% The current color in driver-dependent format.
% \begin{macrocode}
-%</dvipdfmx|pdfmode|xdvipdfmx>
+\tl_new:N \l_@@_color_current_tl
+\tl_set:Nn \l_@@_color_current_tl { [ 0 ] }
+%<*package>
+\AtBeginDocument
+ {
+ \@ifpackageloaded { color }
+ { \tl_set:Nn \l_@@_color_current_tl { \current at color } }
+ { }
+ }
+%</package>
% \end{macrocode}
+% \end{variable}
%
-% \subsection{\texttt{dvips} driver}
-%
+% \begin{macro}[int]{\@@_color_ensure_current:}
+% \begin{macro}[aux]{\@@_color_reset:}
+% Directly set the color using the specials with optimisation support.
% \begin{macrocode}
-%<*dvips>
+\cs_new_protected:Npn \@@_color_ensure_current:
+ {
+ \tex_special:D { pdf:bcolor~\l_@@_color_current_tl }
+ \group_insert_after:N \@@_color_reset:
+ }
+\cs_new_protected:Npn \@@_color_reset:
+ { \tex_special:D { pdf:ecolor } }
% \end{macrocode}
+% \end{macro}
+% \end{macro}
%
-% \subsubsection{Basics}
+% \subsection{Images}
%
-% \begin{macro}[int]{\@@_literal:n}
-% In the case of \texttt{dvips} there is no build-in saving of the current
-% position, and so some additional PostScript is required to set up the
-% transformation matrix and also to restore it afterwards. Notice the use
-% of the stack to save the current position \enquote{up front} and to
-% move back to it at the end of the process.
+% \begin{macro}[int]
+% {
+% \@@_image_getbb_eps:n, \@@_image_getbb_jpg:n,
+% \@@_image_getbb_pdf:n, \@@_image_getbb_png:n
+% }
+% Simply use the generic functions: only for \texttt{dvipdfmx} in the
+% extraction cases.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_literal:n #1
+\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
+%<*dvipdfmx>
+\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
{
- \tex_special:D
- {
- ps:
- currentpoint~
- currentpoint~translate~
- #1 ~
- neg~exch~neg~exch~translate
- }
+ \int_zero:N \l__image_page_int
+ \tl_clear:N \l__image_pagebox_tl
+ \__image_extract_bb:n {#1}
+ }
+\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
+\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
+ {
+ \bool_set_false:N \l__image_interpolate_tl
+ \__image_extract_bb:n {#1}
}
+%</dvipdfmx>
% \end{macrocode}
% \end{macro}
%
-% \begin{macro}{\@@_scope_begin:, \@@_scope_end:}
-% Scope saving/restoring is done directly with no need to worry about the
-% transformation matrix. General scoping is only for the graphics stack so
-% the lower-cost |gsave|/|grestore| pair are used.
+% \begin{variable}[aux]{\g_@@_image_int}
+% Used to track the object number associated with each image.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_scope_begin:
- { \tex_special:D { ps:gsave } }
-\cs_new_protected:Npn \@@_scope_end:
- { \tex_special:D { ps:grestore } }
+\int_new:N \g_@@_image_int
% \end{macrocode}
-% \end{macro}
-%
-% \subsection{Driver-specific auxiliaries}
+% \end{variable}
%
-% \begin{macro}[int, EXP]{\@@_absolute_lengths:n}
-% The \texttt{dvips} driver scales all absolute dimensions based
-% on the output resolution selected and any \TeX{} magnification. Thus
-% for any operation involving absolute lengths there is a correction to
-% make. This is based on \texttt{normalscale} from \texttt{special.pro}
-% but using the stack rather than a definition to save the current matrix.
+% \begin{macro}[int]
+% {
+% \@@_image_include_eps:n, \@@_image_include_jpg:n,
+% \@@_image_include_pdf:n, \@@_image_include_png:n
+% }
+% \begin{macro}[aux]{\@@_image_include_auxi:nn}
+% \begin{macro}[aux]{\@@_image_include_auxii:nnn, \@@_image_include_auxii:xnn}
+% \begin{macro}[aux]{\@@_image_include_auxiii:nn}
+% The special syntax depends on the file type. There is a difference in
+% how PDF images are best handled between |dvipdfmx| and |xdvipdfmx|: for
+% the latter it is better to use the primitive route. The relevant code for
+% that is included later in this file.
% \begin{macrocode}
-\cs_new:Npn \@@_absolute_lengths:n #1
+\cs_new_protected:Npn \@@_image_include_eps:n #1
{
- matrix~currentmatrix~
- Resolution~72~div~VResolution~72~div~scale~
- DVImag~dup~scale~
- #1 ~
- setmatrix
+ \tex_special:D { PSfile = #1 }
}
+\cs_new_protected:Npn \@@_image_include_jpg:n #1
+ { \@@_image_include_auxi:nn {#1} { image } }
+\cs_new_eq:NN \@@_image_include_png:n \@@_image_include_jpg:n
+%<*dvipdfmx>
+\cs_new_protected:Npn \@@_image_include_pdf:n #1
+ { \@@_image_include_auxi:nn {#1} { epdf } }
+%</dvipdfmx>
% \end{macrocode}
-% \end{macro}
-%
-% \subsubsection{Box operations}
-%
-% \begin{macro}{\@@_box_use_clip:N}
-% Much the same idea as for the PDF mode version but with a slightly
-% different syntax for creating the clip path. To avoid any scaling
-% issues we need the absolute length auxiliary here.
+% Image inclusion is set up to use the fact that each image is stored in
+% the PDF as an XObject. This means that we can include repeated images
+% only once and refer to them. To allow that, track the nature of each
+% image: much the same as for the direct PDF mode case.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_clip:N #1
+\cs_new_protected:Npn \@@_image_include_auxi:nn #1#2
{
- \@@_scope_begin:
- \@@_literal:n
+ \@@_image_include_auxii:xnn
{
- \@@_absolute_lengths:n
- {
- 0 ~
- \dim_to_decimal_in_bp:n { \box_dp:N #1 } ~
- \dim_to_decimal_in_bp:n { \box_wd:N #1 } ~
- \dim_to_decimal_in_bp:n { -\box_ht:N #1 - \box_dp:N #1 } ~
- rectclip
- }
+ \tl_if_empty:NF \l__image_pagebox_tl
+ { : \l__image_pagebox_tl }
+ \int_compare:nNnT \l__image_page_int > 1
+ { :P \int_use:N \l__image_page_int }
+ \bool_if:NT \l__image_interpolate_bool
+ { :I }
}
- \hbox_overlap_right:n { \box_use:N #1 }
- \@@_scope_end:
- \skip_horizontal:n { \box_wd:N #1 }
+ {#1} {#2}
+ }
+\cs_new_protected:Npn \@@_image_include_auxii:nnn #1#2#3
+ {
+ \int_if_exist:cTF { c__image_ #2#1 _int }
+ {
+ \tex_special:D
+ { pdf:usexobj~@image \int_use:c { c__image_ #2#1 _int } }
+ }
+ { \@@_image_include_auxiii:nn {#2} {#1} {#3} }
}
+\cs_generate_variant:Nn \@@_image_include_auxii:nnn { x }
% \end{macrocode}
-% \end{macro}
-%
-% \begin{macro}{\@@_box_use_rotate:Nn}
-% Rotating using \texttt{dvips} does not require that the box dimensions
-% are altered and has a very convenient built-in operation. Zero rotation
-% must be written as |0| not |-0| so there is a quick test.
+% Inclusion using the specials is relatively straight-forward, but there
+% is one wrinkle. To get the |pagebox| correct for PDF images in all cases,
+% it is necessary to provide both that information and the |bbox| argument:
+% odd things happen otherwise!
% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2
+\cs_new_protected:Npn \@@_image_include_auxiii:nnn #1#2#3
{
- \@@_scope_begin:
- \@@_literal:n
+ \int_gincr:N \g_@@_image_int
+ \int_const:cn { c__image_ #1#2 _int } { \g_@@_image_int }
+ \tex_special:D
{
- \fp_compare:nNnTF {#2} = \c_zero_fp
- { 0 }
- { \fp_eval:n { round ( -#2 , 5 ) } } ~
- rotate
+ pdf:#3~
+ @image \int_use:c { c__image_ #1#2 _int }
+ \int_compare:nNnT \l__image_page_int > 1
+ { page ~ \int_use:N \l__image_page_int \c_space_tl }
+ \tl_if_empty:NF \l__image_pagebox_tl
+ {
+ pagebox ~ \l__image_pagebox_tl \c_space_tl
+ bbox ~
+ \dim_to_decimal_in_bp:n \l__image_llx_dim \c_space_tl
+ \dim_to_decimal_in_bp:n \l__image_lly_dim \c_space_tl
+ \dim_to_decimal_in_bp:n \l__image_urx_dim \c_space_tl
+ \dim_to_decimal_in_bp:n \l__image_ury_dim \c_space_tl
+ }
+ (#1)
+ \bool_if:NT \l__image_interpolate_bool
+ { <</Interpolate~true>> }
}
- \box_use:N #1
- \@@_scope_end:
}
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
% \end{macro}
%
-% \begin{macro}{\@@_box_use_scale:Nnn}
-% The \texttt{dvips} driver once again has a dedicated operation we can
-% use here.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_box_use_scale:Nnn #1#2#3
- {
- \@@_scope_begin:
- \@@_literal:n
- {
- \fp_eval:n { round ( #2 , 5 ) } ~
- \fp_eval:n { round ( #3 , 5 ) } ~
- scale
- }
- \hbox_overlap_right:n { \box_use:N #1 }
- \@@_scope_end:
- }
+%</dvipdfmx|xdvipdfmx>
+% \end{macrocode}
+%
+% \subsection{\texttt{xdvipdfmx} driver}
+%
+% \begin{macrocode}
+%<*xdvipdfmx>
% \end{macrocode}
-% \end{macro}
%
% \subsubsection{Color}
%
-% \begin{variable}{\l_@@_color_current_tl}
-% The current color in driver-dependent format.
+% \begin{macro}[int]{\@@_color_ensure_current:}
+% \begin{macro}[aux]{\@@_color_reset:}
+% Older \LaTeXe{} drivers uses \texttt{dvips}-like specials so there has to
+% be a change of set up if \pkg{color} is loaded and if the current color
+% doesn't match the pattern expected for |dvipdfmx|.
% \begin{macrocode}
-\tl_new:N \l_@@_color_current_tl
-\tl_set:Nn \l_@@_color_current_tl { gray~0 }
%<*package>
\AtBeginDocument
{
\@ifpackageloaded { color }
- { \tl_set:Nn \l_@@_color_current_tl { \current at color } }
+ {
+ \cs_set_protected:Npn \@@_tmp:w #1 [ #2 ] #3 \q_stop
+ {
+ \tl_if_empty:nT {#2}
+ {
+ \cs_set_protected:Npn \@@_color_ensure_current:
+ {
+ \tex_special:D { color~push~\l_@@_color_current_tl }
+ \group_insert_after:N \@@_color_reset:
+ }
+ \cs_set_protected:Npn \@@_color_reset:
+ { \tex_special:D { color~pop } }
+ }
+ }
+ \exp_after:wN \@@_tmp:w \current at color [ ] \q_stop
+ }
{ }
}
%</package>
% \end{macrocode}
-% \end{variable}
-%
-% \begin{macro}[int]{\@@_color_ensure_current:}
-% \begin{macro}[aux]{\@@_color_reset:}
-% Directly set the color using the specials: no optimisation here.
-% \begin{macrocode}
-\cs_new_protected:Npn \@@_color_ensure_current:
- {
- \tex_special:D { color~push~\l_@@_color_current_tl }
- \group_insert_after:N \@@_color_reset:
- }
-\cs_new_protected:Npn \@@_color_reset:
- { \tex_special:D { color~pop } }
-% \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Images}
%
-% \begin{macro}[int]{\@@_image_getbb_eps:n}
-% Simply use the generic function.
+% \begin{macro}[int]
+% {\@@_image_getbb_jpg:n, \@@_image_getbb_pdf:n, \@@_image_getbb_png:n}
+% \begin{macro}[aux]{\@@_image_getbb_auxi:nN}
+% \begin{macro}[aux]{\@@_image_getbb_auxii:nnN, \@@_image_getbb_auxii:VnN}
+% \begin{macro}[aux]{\@@_image_getbb_auxiii:nNnn}
+% \begin{macro}[aux]{\@@_image_getbb_auxiv:nnNnn, \@@_image_getbb_auxiv:VnNnn}
+% \begin{macro}[aux]{\@@_image_getbb_auxv:nNnn, \@@_image_getbb_auxv:nNnn}
+% \begin{macro}[aux, EXP]{\@@_image_getbb_pagebox:w}
+% For \texttt{xdvipdfmx}, there are two primitives that allow us to obtain
+% the bounding box without needing \texttt{extractbb}. The only complexity
+% is passing the various minor variations to a common core process. The
+% \XeTeX{} primitive omits the text |box| from the page box specification,
+% so there is also some \enquote{trimming} to do here.
% \begin{macrocode}
-\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n
+\cs_new_protected:Npn \@@_image_getbb_jpg:n #1
+ {
+ \int_zero:N \l__image_page_int
+ \@@_image_getbb_auxi:nN {#1} \xetex_picfile:D
+ }
+\cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n
+\cs_new_protected:Npn \@@_image_getbb_pdf:n #1
+ { \@@_image_getbb_auxi:nN {#1} \xetex_pdffile:D }
+\cs_new_protected:Npn \@@_image_getbb_auxi:nN #1#2
+ {
+ \int_compare:nNnTF \l__image_page_int > 1
+ { \@@_image_getbb_auxii:VnN \l__image_page_int {#1} #2 }
+ { \@@_image_getbb_auxiii:nNnn {#1} #2 }
+ }
+\cs_new_protected:Npn \@@_image_getbb_auxii:nnN #1#2#3
+ { \@@_image_getbb_aux:nNnn {#2} #3 { :P #1 } { page #1 } }
+\cs_generate_variant:Nn \@@_image_getbb_auxii:nnN { V }
+\cs_new_protected:Npn \@@_image_getbb_auxiii:nNnn #1#2#3#4
+ {
+ \tl_if_empty:NTF \l__image_pagebox_tl
+ { \@@_image_getbb_auxiv:VnNnn \l__image_pagebox_tl }
+ { \@@_image_getbb_auxv:nNnn }
+ {#1} #2 {#3} {#4}
+ }
+\cs_new_protected:Npn \@@_image_getbb_auxiv:nnNnn #1#2#3#4#5
+ {
+ \use:x
+ {
+ \@@_image_getbb_auxv:nNnn {#2} #3 { : #1 #4 }
+ { #5 ~ \@@_image_getbb_pagebox:w #1 }
+ }
+ }
+\cs_generate_variant:Nn \@@_image_getbb_auxiv:nnNnn { V }
+\cs_new_protected:Npn \@@_image_getbb_auxv:nNnn #1#2#3#4
+ {
+ \dim_zero:N \l__image_llx_dim
+ \dim_zero:N \l__image_lly_dim
+ \dim_if_exist:cTF { c__image_ #1#3 _urx_dim }
+ {
+ \dim_set_eq:Nc \l__image_urx_dim { c__image_ #1#3 _urx_dim }
+ \dim_set_eq:Nc \l__image_ury_dim { c__image_ #1#3 _ury_dim }
+ }
+ { \@@_image_getbb_auxvi:nNnn {#1} #2 {#3} {#4} }
+ }
+\cs_new_protected:Npn \@@_image_getbb_auxvi:nNnn #1#2#3#4
+ {
+ \hbox_set:Nn \l__image_tmp_box { #2 #1 ~ #4 }
+ \dim_set:Nn \l__image_utx_dim { \box_wd:N \l__image_tmp_box }
+ \dim_set:Nn \l__image_ury_dim { \box_ht:N \l__image_tmp_box }
+ \dim_const:cn { c__image_ #1#3 _urx_dim }
+ { \l__image_urx_dim }
+ \dim_const:cn { c__image_ #1#3 _ury_dim }
+ { \l__image_ury_dim }
+ }
+\cs_new:Npn \@@_image_getbb_pagebox:w #1 box {#1}
% \end{macrocode}
% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
%
-% \begin{macro}[int]{\@@_image_include_eps:n}
-% The special syntax is relatively clear here: remember we need PostScript
-% sizes here.
+% \begin{macro}[int]{\@@_image_include_pdf:n}
+% For PDF images, properly supporting the |pagebox| concept in \XeTeX{}
+% is best done using the |\xetex_pdffile:D| primitive. The syntax here
+% is the same as for the image measurement part, although we know at this
+% stage that there must be some valid setting for \cs{l__image_pagebox_tl}.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_image_include_eps:n #1
+\cs_new_protected:Npn \@@_image_include_pdf:n #1
{
- \tex_special:D { PSfile = #1 }
+ \xetex_pdffile:D "#1" ~
+ \int_compare:nNnT \l__image_page_int > 0
+ { page~ \int_use:N \l__image_page_int }
+ \@@_image_getbb_auxiv:VnNnn \l__image_pagebox_tl
}
% \end{macrocode}
% \end{macro}
%
+% \begin{macrocode}
+%</xdvipdfmx>
+% \end{macrocode}
+%
+% \subsection{Drawing commands: \texttt{pdfmode} and \texttt{(x)dvipdfmx}}
+%
+% Both \texttt{pdfmode} and \texttt{(x)dvipdfmx} directly produce PDF output
+% and understand a shared set of specials for drawing commands.
+%
+% \begin{macrocode}
+%<*dvipdfmx|pdfmode|xdvipdfmx>
+% \end{macrocode}
+%
% \subsection{Drawing}
%
% \begin{macro}[aux]{\@@_draw_literal:n, \@@_draw_literal:x}
-% Literals with no positioning (using |ps:| each one is positioned but
-% cut off from everything else, so no good for the stepwise approach needed
-% here).
+% Pass data through using a dedicated interface.
% \begin{macrocode}
-\cs_new_protected:Npn \@@_draw_literal:n #1
- { \tex_special:D { ps:: ~ #1 } }
+\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:}
-% 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.
+% No special requirements here, so simply set up a drawing scope.
% \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 }
- }
+ { \@@_draw_scope_begin: }
\cs_new_protected:Npn \@@_draw_end:
- {
- \tex_special:D { ps::~@endspecial }
- \tex_special:D { ps::~restore }
- \tex_special:D { ps::[end] }
- }
+ { \@@_draw_scope_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.
+% 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:Npn \@@_draw_scope_begin:
- { \@@_draw_literal:n { save } }
+ { \@@_draw_literal:n { q } }
\cs_new_protected:Npn \@@_draw_scope_end:
- { \@@_draw_literal:n { restore } }
+ { \@@_draw_literal:n { Q } }
% \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{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
+% forced to literals before any possible caching.
% \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 }
+ { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ m }
}
\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~closepath
- }
+ { \dim_to_decimal_in_bp:n {#1} ~ \dim_to_decimal_in_bp:n {#2} ~ l }
}
\cs_new_protected:Npn \@@_draw_curveto:nnnnnn #1#2#3#4#5#6
{
@@ -1813,16 +1883,25 @@
\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
+ 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{macro}[int]{\@@_draw_evenodd_rule:, \@@_draw_nonzero_rule:}
-% \begin{variable}[aux]{\g_@@_draw_eor_bool}
+% \begin{variable}[int]{\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:
@@ -1843,102 +1922,34 @@
% \@@_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).
+% }
+% Converting paths to output is again a case of mapping directly to
+% PDF operations.
% \begin{macrocode}
\cs_new_protected:Npn \@@_draw_closepath:
- { \@@_draw_literal:n { closepath } }
+ { \@@_draw_literal:n { h } }
\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
- }
+ { \@@_draw_literal:n { S } }
\cs_new_protected:Npn \@@_draw_closestroke:
- {
- \@@_draw_closepath:
- \@@_draw_stroke:
- }
+ { \@@_draw_literal:n { s } }
\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
+ { f \bool_if:NT \g_@@_draw_eor_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
+ { B \bool_if:NT \g_@@_draw_eor_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
+ \@@_draw_literal:x
+ { W \bool_if:NT \g_@@_draw_eor_bool * }
}
+\cs_new_protected:Npn \@@_draw_discardpath:
+ { \@@_draw_literal:n { n } }
% \end{macrocode}
-% \end{variable}
% \end{macro}
%
% \begin{macro}[int]{\@@_draw_dash:nn}
@@ -1951,7 +1962,7 @@
% \@@_draw_join_miter:, \@@_draw_join_round:, \@@_draw_join_bevel:
% }
% Converting paths to output is again a case of mapping directly to
-% PostScript operations.
+% PDF operations.
% \begin{macrocode}
\cs_new_protected:Npn \@@_draw_dash:nn #1#2
{
@@ -1960,7 +1971,7 @@
[ ~
\clist_map_function:nN {#1} \@@_draw_dash:n
] ~
- \dim_to_decimal_in_bp:n {#2} ~ setdash
+ \dim_to_decimal_in_bp:n {#2} ~ d
}
}
\cs_new:Npn \@@_draw_dash:n #1
@@ -1968,22 +1979,22 @@
\cs_new_protected:Npn \@@_draw_linewidth:n #1
{
\@@_draw_literal:x
- { \dim_to_decimal_in_bp:n {#1} ~ setlinewidth }
+ { \dim_to_decimal_in_bp:n {#1} ~ w }
}
\cs_new_protected:Npn \@@_draw_miterlimit:n #1
- { \@@_draw_literal:x { \fp_eval:n {#1} ~ setmiterlimit } }
+ { \@@_draw_literal:x { \fp_eval:n {#1} ~ M } }
\cs_new_protected:Npn \@@_draw_cap_butt:
- { \@@_draw_literal:n { 0 ~ setlinecap } }
+ { \@@_draw_literal:n { 0 ~ J } }
\cs_new_protected:Npn \@@_draw_cap_round:
- { \@@_draw_literal:n { 1 ~ setlinecap } }
+ { \@@_draw_literal:n { 1 ~ J } }
\cs_new_protected:Npn \@@_draw_cap_rectangle:
- { \@@_draw_literal:n { 2 ~ setlinecap } }
+ { \@@_draw_literal:n { 2 ~ J } }
\cs_new_protected:Npn \@@_draw_join_miter:
- { \@@_draw_literal:n { 0 ~ setlinejoin } }
+ { \@@_draw_literal:n { 0 ~ j } }
\cs_new_protected:Npn \@@_draw_join_round:
- { \@@_draw_literal:n { 1 ~ setlinejoin } }
+ { \@@_draw_literal:n { 1 ~ j } }
\cs_new_protected:Npn \@@_draw_join_bevel:
- { \@@_draw_literal:n { 2 ~ setlinejoin } }
+ { \@@_draw_literal:n { 2 ~ j } }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1991,118 +2002,109 @@
% \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}[aux]{\@@_draw_color_cmyk_aux:nnnn}
% \begin{macro}[int]
% {
% \@@_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: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{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_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
+ \use:x
{
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- setcmykcolor ~
+ \@@_draw_color_cmyk_aux:nnnn
+ { \fp_eval:n {#1} }
+ { \fp_eval:n {#2} }
+ { \fp_eval:n {#3} }
+ { \fp_eval:n {#4} }
}
- \@@_draw_color_reset:
+ }
+\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
{
- /l3fc ~
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- setcmykcolor
- } ~
- def
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+ \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+ k
}
}
\cs_new_protected:Npn \@@_draw_color_cmyk_stroke:nnnn #1#2#3#4
{
- \__driver_draw_literal:x
+ \@@_draw_literal:x
{
- /l3sc ~
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
- \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
- setcmykcolor
- } ~
- def
+ \fp_eval:n {#1} ~ \fp_eval:n {#2} ~
+ \fp_eval:n {#3} ~ \fp_eval:n {#4} ~
+ K
}
}
\cs_new_protected:Npn \@@_draw_color_gray:n #1
{
- \@@_draw_literal:x { fp_eval:n {#1} ~ setgray }
- \@@_draw_color_reset:
+ \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 { /l3fc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
+ { \@@_draw_literal:x { \fp_eval:n {#1} ~ g } }
\cs_new_protected:Npn \@@_draw_color_gray_stroke:n #1
- { \@@_draw_literal:x { /l3sc ~ { \fp_eval:n {#1} ~ setgray } ~ def } }
+ { \@@_draw_literal:x { \fp_eval:n {#1} ~ G } }
\cs_new_protected:Npn \@@_draw_color_rgb:nnn #1#2#3
{
- \@@_draw_literal:x
+ \use:x
{
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
- setrgbcolor
+ \@@_draw_color_rgb_aux:nnn
+ { \fp_eval:n {#1} }
+ { \fp_eval:n {#2} }
+ { \fp_eval:n {#3} }
}
- \@@_draw_color_reset:
+ }
+\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
- {
- /l3fc ~
- {
- \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~
- setrgbcolor
- } ~
- def
- }
+ { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ rg }
}
\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
- }
+ { \fp_eval:n {#1} ~ \fp_eval:n {#2} ~ \fp_eval:n {#3} ~ RG }
}
% \end{macrocode}
% \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
@@ -2113,49 +2115,47 @@
{
\@@_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
+ \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} ~
+ cm
}
}
% \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{variable}[aux]{\l_@@_tmp_box}
+% Inserting a \TeX{} box transformed to the requested position and using
+% the current matrix is done using a mixture of \TeX{} and low-level
+% manipulation. The offset can be handled by \TeX{}, so only any rotation/^^A
+% skew/scaling component needs to be done using the matrix operation. As this
+% operation can never be cached, the scope is set directly not using the
+% \texttt{draw} version.
% \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:
+ \hbox_set:Nn \l_@@_tmp_box
+ {
+ \tex_kern:D \__dim_eval:w #6 \__dim_eval_end:
+ \@@_scope_begin:
+ \@@_draw_transformcm:nnnnnn {#2} {#3} {#4} {#5}
+ { 0pt } { 0pt }
+ \box_move_up:nn {#7} { \box_use:N #1 }
+ \@@_scope_end:
+ }
+ \box_set_wd:Nn \l_@@_tmp_box { 0pt }
+ \box_set_ht:Nn \l_@@_tmp_box { 0pt }
+ \box_set_dp:Nn \l_@@_tmp_box { 0pt }
+ \box_use:N \l_@@_tmp_box
}
+\box_new:N \l_@@_tmp_box
% \end{macrocode}
+% \end{variable}
% \end{macro}
%
% \begin{macrocode}
-%</dvips>
+%</dvipdfmx|pdfmode|xdvipdfmx>
% \end{macrocode}
%
% \subsection{\texttt{dvisvgm} driver}
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the latex3-commits
mailing list