diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx | 1739 |
1 files changed, 930 insertions, 809 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx index 68bb90ec8cc..c6ecb231a2f 100644 --- a/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx +++ b/Master/texmf-dist/source/latex/l3kernel/l3drivers.dtx @@ -45,7 +45,7 @@ % }^^A % } % -% \date{Released 2017/05/29} +% \date{Released 2017/07/15} % % \maketitle % @@ -81,7 +81,7 @@ % \cs{__driver_box_use_clip:N} \meta{box} % \end{syntax} % Inserts the content of the \meta{box} at the current insertion point -% such that any material outside of the bounding box will not be displayed +% such that any material outside of the bounding box is not displayed % by the driver. The material in the \meta{box} is still placed in the % output stream: the clipping takes place at a driver level. % @@ -156,7 +156,7 @@ % \meta{content} % \cs{__driver_draw_end:} % \end{syntax} -% Defines a drawing environment. This will be a scope for the purposes of +% Defines a drawing environment. This is a scope for the purposes of % the graphics state. Depending on the driver, other set up may or may not % take place here. The natural size of the \meta{content} should be zero % from the \TeX{} perspective: allowance for the size of the content must @@ -186,7 +186,7 @@ % \cs{__driver_draw_move:nn} \Arg{x} \Arg{y} % \end{syntax} % Moves the current drawing reference point to (\meta{x}, \meta{y}); -% any active transformation matrix will apply. +% any active transformation matrix applies. % \end{function} % % \begin{function}{\__driver_draw_lineto:nn} @@ -194,7 +194,7 @@ % \cs{__driver_draw_lineto:nn} \Arg{x} \Arg{y} % \end{syntax} % Adds a path from the current drawing reference point to -% (\meta{x}, \meta{y}); any active transformation matrix will apply. Note +% (\meta{x}, \meta{y}); any active transformation matrix applies. 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} @@ -207,7 +207,7 @@ % Adds a Bezier curve path from the current drawing reference point to % (\meta{x_3}, \meta{y_3}), using (\meta{x_1}, \meta{y_1}) and % (\meta{x_2}, \meta{y_2}) as control points; any active transformation -% matrix will apply. Note that nothing is drawn until a fill or stroke +% matrix applies. 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} @@ -217,7 +217,7 @@ % \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 +% and \meta{width}; any active transformation matrix applies. 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} @@ -239,8 +239,8 @@ % \meta{path construction} % \cs{__driver_draw_stroke:} % \end{syntax} -% Draws a line alone the current path, which will also be closed when -% \cs{__driver_draw_closestroke:} is used. The nature of the line drawn +% Draws a line along the current path, which is also closed by +% \cs{__driver_draw_closestroke:}. The nature of the line drawn % is influenced by settings for % \begin{itemize} % \item Line thickness @@ -259,8 +259,8 @@ % \cs{__driver_draw_fill:} % \end{syntax} % Fills the area surrounded by the current path: this will be closed prior -% to filling if it is not already. The \texttt{fillstroke} version will also -% stroke the path as described for \cs{__driver_draw_stroke:}. The fill is +% to filling if it is not already. The \texttt{fillstroke} version also +% strokes the path as described for \cs{__driver_draw_stroke:}. The fill is % 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 @@ -325,7 +325,7 @@ % \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 +% example, with a pattern \texttt{3pt} a phase of \texttt{1pt} means % that the output is $2$\,pt on, $3$\,pt off, $3$\,pt on, $3$\,pt on, % \emph{etc.} % \end{function} @@ -422,12 +422,12 @@ % \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 +% at ($x$, $y$). The transformation matrix $[a b c d]$ is 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. +% be inserted directly into a drawing as it would not be in the correct +% location. Also note that as for other drawing elements the box here +% has no size from a \TeX{} perspective. % \end{function} % % \subsection{Coordinate system transformations} @@ -438,7 +438,7 @@ % \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 +% ($x$, $y$) to the current graphic state. This affects any subsequent % items in the same scope but not those already given. % \end{function} % @@ -487,6 +487,752 @@ %</package> % \end{macrocode} % +% The order of the driver code here is such that we get somewhat logical +% outcomes in terms of code sharing whilst keeping things readable. (Trying to +% mix all of the code by concept is almost unmanageable.) The key parts which +% are shared are +% \begin{itemize} +% \item Color support is either \texttt{dvips}-like or \texttt{pdfmode}-like. +% \item \texttt{pdfmode} and \texttt{(x)dvipdfmx} share drawing routines. +% \item \texttt{xdvipdfmx} is largely the same as \texttt{dvipdfmx} so +% takes most of the same code. +% \end{itemize} +% +% \subsection{Color support} +% +% Whilst \texttt{(x)dvipdfmx} does have its own approach to color specials, +% it is easier to use \texttt{dvips}-like ones for all cases except direct +% PDF output. As such the color code is collected here in two blocks. +% +% \subsubsection{\texttt{dvips}-style} +% +% \begin{macrocode} +%<*dvisvgm|dvipdfmx|dvips|xdvipdfmx> +% \end{macrocode} +% +% \begin{macro}[aux]{\@@_color_pickup:} +% Allow for \LaTeXe{}. +% \begin{macrocode} +%<*package> +\AtBeginDocument + { + \@ifpackageloaded { color } + { + \cs_new_protected:Npn \@@_color_pickup: + { \tl_set_eq:NN \l__color_current_tl \current@color } + } + { \cs_new_protected:Npn \@@_color_pickup: { } } + } +%</package> +% \end{macrocode} +% \end{macro} +% +% \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: + { +%<*package> + \@@_color_pickup: +%</package> + \tex_special:D { color~push~\l__color_current_tl } + } +\cs_new_protected:Npn \@@_color_reset: + { \tex_special:D { color~pop } } +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</dvisvgm|dvipdfmx|dvips|xdvipdfmx> +% \end{macrocode} +% +% \subsubsection{\texttt{pdfmode}} +% +% \begin{macrocode} +%<*pdfmode> +% \end{macrocode} +% +% \begin{macro}[aux]{\@@_color_pickup:} +% \begin{macro}[aux]{\@@_color_pickup_aux:} +% The current color in driver-dependent format: pick up the package-mode +% data if available. We end up converting back and forward in this route as +% we store our color data in \texttt{dvips} format. +% \begin{macrocode} +%<*package> +\AtBeginDocument + { + \@ifpackageloaded { color } + { + \cs_new_protected:Npn \@@_color_pickup: + { + \tl_set:Nx \l__color_current_tl + { + \exp_after:wN \@@_color_pickup_aux:w + \current@color ~ 0 ~ 0 ~ 0 \q_stop + } + } + \cs_new:Npn \@@_color_pickup_aux:w #1 ~ #2 ~ #3 ~ #4 ~ #5 ~ #6 \q_stop + { + \str_if_eq:nnTF {#2} { g } + { gray ~ #1 } + { + \str_if_eq:nnTF {#4} { rg } + { rgb ~ #1 ~ #2 ~ #3 } + { + \str_if_eq:nnTF {#5} { k } + { cmyk ~ #1 ~ #2 ~ #3 ~ #4 } + { gray ~ #1 } + } + } + } + } + { \cs_new_protected:Npn \@@_color_pickup: { } } + } +%</package> +% \end{macrocode} +% \end{macro} +% \end{macro} +% +% \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, EXP] +% { +% \@@_color_convert:w, \@@_color_convert_gray:w, +% \@@_color_convert_cmyk:w, \@@_color_convert_rgb:w +% } +% \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. +% Since we are using the \texttt{dvips} format to store color, there is a +% bit of work to correctly place it in the output. +% \begin{macrocode} +\cs_new_protected:Npx \@@_color_ensure_current: + { +%<*package> + \exp_not:N \@@_color_pickup: +%</package> + \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 \exp_after:wN + \exp_not:N \@@_color_convert:w + \exp_not:N \l__color_current_tl + \c_space_tl 0 ~ 0 ~ 0 + \exp_not:N \q_stop + } + } +\cs_new:Npn \@@_color_convert:w #1 ~ + { \use:c { @@_color_convert_ #1 :w } } +\cs_new:Npn \@@_color_convert_gray:w #1 ~ #2 \q_stop + { #1 ~ g ~ #1 ~ G } +\cs_new:Npn \@@_color_convert_cmyk:w #1 ~ #2 ~ #3 ~ #4 \q_stop + { #1 ~ #2 ~ #3 ~ rg ~ #1 ~ #2 ~ #3 ~ RG } +\cs_new:Npn \@@_color_convert_rgb:w #1 ~ #2 ~ #3 ~ #4 ~ #5 \q_stop + { #1 ~ #2 ~ #3 ~ #4 ~ k ~ #1 ~ #2 ~ #3 ~ #4 ~ K } +\cs_new_protected:Npx \@@_color_reset: + { + \cs_if_exist:NTF \luatex_pdfextension:D + { \luatex_pdfextension:D colorstack } + { \pdftex_pdfcolorstack:D } + \exp_not:N \l_@@_color_stack_int pop \scan_stop: + } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</pdfmode> +% \end{macrocode} +% +% \subsection{\texttt{dvips} driver} +% +% \begin{macrocode} +%<*dvips> +% \end{macrocode} +% +% \subsubsection{Basics} +% +% \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{macrocode} +\cs_new_protected:Npn \@@_literal:n #1 + { + \tex_special:D + { + ps: + currentpoint~ + currentpoint~translate~ + #1 ~ + neg~exch~neg~exch~translate + } + } +% \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{macrocode} +\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} +% +% \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:Npn \@@_absolute_lengths:n #1 + { + matrix~currentmatrix~ + Resolution~72~div~VResolution~72~div~scale~ + DVImag~dup~scale~ + #1 ~ + setmatrix + } +% \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. +% \begin{macrocode} +\cs_new_protected:Npn \@@_box_use_clip:N #1 + { + \@@_scope_begin: + \@@_literal: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: + \skip_horizontal:n { \box_wd:N #1 } + } +% \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. +% \begin{macrocode} +\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2 + { + \@@_scope_begin: + \@@_literal:n + { + \fp_compare:nNnTF {#2} = \c_zero_fp + { 0 } + { \fp_eval:n { round ( -#2 , 5 ) } } ~ + rotate + } + \box_use:N #1 + \@@_scope_end: + } +% \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: + } +% \end{macrocode} +% \end{macro} +% +% \subsection{Images} +% +% \begin{macro}[int]{\@@_image_getbb_eps:n} +% Simply use the generic function. +% \begin{macrocode} +\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n +% \end{macrocode} +% \end{macro} +% +% \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_include_eps:n #1 + { + \tex_special:D { PSfile = #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: + { + \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~closepath + } + } +\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 would be off +% if the box was 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} +% % \subsection{\texttt{pdfmode} driver} % % \begin{macrocode} @@ -638,58 +1384,6 @@ % \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 - { - \@ifpackageloaded { color } - { \tl_set:Nn \l_@@_color_current_tl { \current@color } } - { } - } -%</package> -% \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. -% \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_if_exist:NTF \luatex_pdfextension:D - { \luatex_pdfextension:D colorstack } - { \pdftex_pdfcolorstack:D } - \exp_not:N \l_@@_color_stack_int pop \scan_stop: - } -% \end{macrocode} -% \end{macro} -% \end{macro} -% % \subsection{Images} % % \begin{variable}{\l_@@_image_attr_tl} @@ -713,64 +1407,84 @@ % 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. Note that -% in |pdftex.def| the short reference is stored to be used in the inclusion -% stage: may be required when there are more aspects to track. +% track for caching, and the full form to pass to the primitive. % \begin{macrocode} \cs_new_protected:Npn \@@_image_getbb_jpg:n #1 { \int_zero:N \l__image_page_int + \tl_clear:N \l__image_pagebox_tl \tl_set:Nx \l_@@_image_attr_tl { + \tl_if_empty:NF \l__image_decode_tl + { :D \l__image_decode_tl } \bool_if:NT \l__image_interpolate_bool { :I } } + \tl_clear:N \l_@@_image_attr_tl \@@_image_getbb_auxi:n {#1} } \cs_new_eq:NN \@@_image_getbb_png:n \@@_image_getbb_jpg:n \cs_new_protected:Npn \@@_image_getbb_pdf:n #1 { + \tl_clear:N \l__image_decode_tl \bool_set_false:N \l__image_interpolate_bool \tl_set:Nx \l_@@_image_attr_tl { - \int_compare:nNnT \l__image_page_int > 0 + : \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_if_exist:cTF { c__image_ #1 \l_@@_image_attr_tl _ht_dim } + \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_ht_dim - { c__image_ #1 \l_@@_image_attr_tl _ht_dim } - \dim_set_eq:Nc \l__image_wd_dim - { c__image_ #1 \l_@@_image_attr_tl _wd_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 always starts 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 } } + \bool_lazy_or:nnT + { \l__image_interpolate_bool } + { ! \tl_if_empty_p:N \l__image_decode_tl } + { + attr ~ + { + \tl_if_empty:NF \l__image_decode_tl + { /Decode~[ \l__image_decode_tl ] } + \bool_if:NT \l__image_interpolate_bool + { /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_ht_dim { \box_ht:N \l__image_tmp_box } - \dim_set:Nn \l__image_wd_dim { \box_wd:N \l__image_tmp_box } + \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 _ht_dim } - { \l__image_ht_dim } - \dim_const:cn { c__image_ #1 \l_@@_image_attr_tl _wd_dim } - { \l__image_wd_dim } + \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 } } % \end{macrocode} % \end{macro} @@ -858,7 +1572,7 @@ % \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 +% of the content of boxes: this means that any embedded links would 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 @@ -899,39 +1613,6 @@ % \end{macrocode} % \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@color } } - { } - } -%</package> -% \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] @@ -947,12 +1628,14 @@ \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 { - \bool_set_false:N \l__image_interpolate_tl + \tl_clear:N \l__image_decode_tl + \bool_set_false:N \l__image_interpolate_bool \__image_extract_bb:n {#1} } %</dvipdfmx> @@ -974,7 +1657,10 @@ % \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. +% 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 { @@ -982,9 +1668,11 @@ } \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_png:n +\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 @@ -995,8 +1683,12 @@ { \@@_image_include_auxii:xnn { - \int_compare:nNnT \l__image_page_int > 0 + \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 } + \tl_if_empty:NF \l__image_decode_tl + { :D \l__image_decode_tl } \bool_if:NT \l__image_interpolate_bool { :I } } @@ -1012,6 +1704,12 @@ { \@@_image_include_auxiii:nn {#2} {#1} {#3} } } \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 { \int_gincr:N \g_@@_image_int @@ -1020,11 +1718,29 @@ { pdf:#3~ @image \int_use:c { c__image_ #1#2 _int } - \int_compare:nNnT \l__image_page_int > 0 + \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>> } + \bool_lazy_or:nnT + { \l__image_interpolate_bool } + { ! \tl_if_empty_p:N \l__imge_decode_tl } + { + << + \tl_if_empty:NF \l__imge_decode_tl + { /Decode~[ \l__imge_decode_tl ] } + \bool_if:NT \l__image_interpolate_bool + { /Interpolate~true> } + >> + } } } % \end{macrocode} @@ -1043,41 +1759,6 @@ %<*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 - { - \@ifpackageloaded { 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@color [ ] \q_stop - } - { } - } -%</package> -% \end{macrocode} -% \end{macro} -% \end{macro} -% % \subsection{Images} % % \begin{macro}[int] @@ -1085,50 +1766,99 @@ % \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 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 { \int_zero:N \l__image_page_int + \tl_clear:N \l__image_pagebox_tl \@@_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 } + { + \tl_clear:N \l__image_decode_tl + \bool_set_false:N \l__image_interpolate_bool + \@@_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 > 0 + \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_auxiii:nNnn {#2} #3 { :P #1 } { page #1 } } + { \@@_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 { - \dim_if_exist:cTF { c__image_ #1#3 _ht_dim } + \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_ht_dim { c__image_ #1#3 _ht_dim } - \dim_set_eq:Nc \l__image_wd_dim { c__image_ #1#3 _wd_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_ht_dim { \box_ht:N \l__image_tmp_box } - \dim_set:Nn \l__image_wd_dim { \box_wd:N \l__image_tmp_box } - \dim_const:cn { c__image_ #1#3 _ht_dim } - { \l__image_ht_dim } - \dim_const:cn { c__image_ #1#3 _wd_dim } - { \l__image_wd_dim } + \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_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 + { + \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> @@ -1474,616 +2204,6 @@ %</dvipdfmx|pdfmode|xdvipdfmx> % \end{macrocode} % -% \subsection{\texttt{dvips} driver} -% -% \begin{macrocode} -%<*dvips> -% \end{macrocode} -% -% \subsubsection{Basics} -% -% \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{macrocode} -\cs_new_protected:Npn \@@_literal:n #1 - { - \tex_special:D - { - ps: - currentpoint~ - currentpoint~translate~ - #1 ~ - neg~exch~neg~exch~translate - } - } -% \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{macrocode} -\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} -% -% \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:Npn \@@_absolute_lengths:n #1 - { - matrix~currentmatrix~ - Resolution~72~div~VResolution~72~div~scale~ - DVImag~dup~scale~ - #1 ~ - setmatrix - } -% \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. -% \begin{macrocode} -\cs_new_protected:Npn \@@_box_use_clip:N #1 - { - \@@_scope_begin: - \@@_literal: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: - \skip_horizontal:n { \box_wd:N #1 } - } -% \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. -% \begin{macrocode} -\cs_new_protected:Npn \@@_box_use_rotate:Nn #1#2 - { - \@@_scope_begin: - \@@_literal:n - { - \fp_compare:nNnTF {#2} = \c_zero_fp - { 0 } - { \fp_eval:n { round ( -#2 , 5 ) } } ~ - rotate - } - \box_use:N #1 - \@@_scope_end: - } -% \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: - } -% \end{macrocode} -% \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 { gray~0 } -%<*package> -\AtBeginDocument - { - \@ifpackageloaded { color } - { \tl_set:Nn \l_@@_color_current_tl { \current@color } } - { } - } -%</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{macrocode} -\cs_new_eq:NN \@@_image_getbb_eps:n \__image_read_bb:n -% \end{macrocode} -% \end{macro} -% -% \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_include_eps:n #1 - { - \tex_special:D { PSfile = #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: - { - \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} -% % \subsection{\texttt{dvisvgm} driver} % % \begin{macrocode} @@ -2253,36 +2373,37 @@ % \end{macrocode} % \end{macro} % -% \subsubsection{Color} +% \subsection{Images} % -% \begin{variable}{\l_@@_color_current_tl} -% The current color in driver-dependent format: the same as for -% \texttt{dvips}. +% \begin{macro}[int]{\@@_image_getbb_png:n, \@@_image_getbb_jpg:n} +% These can be included by extracting the bounding box data. % \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@color } } - { } - } -%</package> +\cs_new_eq:NN \@@_image_getbb_png:n \__image_extract_bb:n +\cs_new_eq:NN \@@_image_getbb_jpg:n \__image_extract_bb:n % \end{macrocode} -% \end{variable} +% \end{macro} % -% \begin{macro}[int]{\@@_color_ensure_current:} -% \begin{macro}[aux]{\@@_color_reset:} -% Directly set the color: same as \texttt{dvips}. +% \begin{macro}[int]{\@@_image_include_png:n, \@@_image_include_jpg:n} +% \begin{macro}[aux]{\@@_image_include_bitmap_quote:w} +% The driver here has built-in support for basic image inclusion (see +% \texttt{dvisvgm.def} for a more complex approach, needed if clipping, +% \emph{etc.}, is covered at the image driver level). The only issue is +% that |#1| must be quote-corrected. The \texttt{dvisvgm:img} operation +% quotes the file name, but if it is already quoted (contains spaces) +% then we have an issue: we simply strip off any quotes as a result. % \begin{macrocode} -\cs_new_protected:Npn \@@_color_ensure_current: +\cs_new_protected:Npn \@@_image_include_png:n #1 { - \tex_special:D { color~push~\l_@@_color_current_tl } - \group_insert_after:N \@@_color_reset: + \tex_special:D + { + dvisvgm:img~ + \dim_to_decimal:n { \l__image_ury_dim } ~ + \dim_to_decimal:n { \l__image_ury_dim } ~ + \@@_image_include_bitmap_quote:w #1 " " \q_stop + } } -\cs_new_protected:Npn \@@_color_reset: - { \tex_special:D { color~pop } } +\cs_new_eq:NN \@@_image_include_jpg:n \@@_image_include_png:n +\cs_new:Npn \@@_image_include_bitmap_quote:w #1 " #2 " #3 \q_stop { #1#2 } % \end{macrocode} % \end{macro} % \end{macro} @@ -2361,7 +2482,7 @@ % 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 +% storage routine, which adds spaces as required. Since paths should % be fully expanded there is no need to worry about the internal % \texttt{x}-type expansion. % \begin{macrocode} |