summaryrefslogtreecommitdiff
path: root/macros/latex/contrib/l3backend/l3backend-basics.dtx
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /macros/latex/contrib/l3backend/l3backend-basics.dtx
Initial commit
Diffstat (limited to 'macros/latex/contrib/l3backend/l3backend-basics.dtx')
-rw-r--r--macros/latex/contrib/l3backend/l3backend-basics.dtx400
1 files changed, 400 insertions, 0 deletions
diff --git a/macros/latex/contrib/l3backend/l3backend-basics.dtx b/macros/latex/contrib/l3backend/l3backend-basics.dtx
new file mode 100644
index 0000000000..930d011cff
--- /dev/null
+++ b/macros/latex/contrib/l3backend/l3backend-basics.dtx
@@ -0,0 +1,400 @@
+% \iffalse meta-comment
+%
+%% File: l3backend-basics.dtx
+%
+% Copyright (C) 2019 The LaTeX3 Project
+%
+% It may be distributed and/or modified under the conditions of the
+% LaTeX Project Public License (LPPL), either version 1.3c of this
+% license or (at your option) any later version. The latest version
+% of this license is in the file
+%
+% https://www.latex-project.org/lppl.txt
+%
+% This file is part of the "l3backend bundle" (The Work in LPPL)
+% and all files in that bundle must be distributed together.
+%
+% -----------------------------------------------------------------------
+%
+% The development version of the bundle can be found at
+%
+% https://github.com/latex3/latex3
+%
+% for those people who are interested.
+%
+%<*driver>
+\documentclass[full,kernel]{l3doc}
+\begin{document}
+ \DocInput{\jobname.dtx}
+\end{document}
+%</driver>
+% \fi
+%
+% \title{^^A
+% The \textsf{l3backend-basics} package\\ Backend basics^^A
+% }
+%
+% \author{^^A
+% The \LaTeX3 Project\thanks
+% {^^A
+% E-mail:
+% \href{mailto:latex-team@latex-project.org}
+% {latex-team@latex-project.org}^^A
+% }^^A
+% }
+%
+% \date{Released 2019-08-25}
+%
+% \maketitle
+%
+% \begin{documentation}
+%
+% \end{documentation}
+%
+% \begin{implementation}
+%
+% \section{\pkg{l3backend-basics} Implementation}
+%
+% \begin{macrocode}
+%<*initex|package>
+% \end{macrocode}
+%
+% Whilst there is a reasonable amount of code overlap between backends,
+% it is much clearer to have the blocks more-or-less separated than run
+% in together and DocStripped out in parts. As such, most of the following
+% is set up on a per-backed basis, though there is some common code (again
+% given in blocks not interspersed with other material).
+%
+% All the file identifiers are up-front so that they come out in the right
+% place in the files.
+% \begin{macrocode}
+%<*package>
+\ProvidesExplFile
+%<*dvipdfmx>
+ {l3backend-dvipdfmx.def}{2019-04-06}{}
+ {L3 Experimental backend support: dvipdfmx}
+%</dvipdfmx>
+%<*dvips>
+ {l3backend-dvips.def}{2019-04-06}{}
+ {L3 Experimental backend support: dvips}
+%</dvips>
+%<*dvisvgm>
+ {l3backend-dvisvgm.def}{2019-04-06}{}
+ {L3 Experimental backend support: dvisvgm}
+%</dvisvgm>
+%<*pdfmode>
+ {l3backend-pdfmode.def}{2019-04-06}{}
+ {L3 Experimental backend support: PDF mode}
+%</pdfmode>
+%<*xdvipdfmx>
+ {l3backend-xdvipdfmx.def}{2019-04-06}{}
+ {L3 Experimental backend support: xdvipdfmx}
+%</xdvipdfmx>
+%</package>
+% \end{macrocode}
+%
+% The order of the backend 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}
+%
+% \begin{macro}
+% {
+% \__kernel_backend_literal:e,
+% \__kernel_backend_literal:n,
+% \__kernel_backend_literal:x
+% }
+% The one shared function for all backends is access to the basic
+% \tn{special} primitive: it has slightly odd expansion behaviour
+% so a wrapper is provided.
+% \begin{macrocode}
+\cs_new_eq:NN \__kernel_backend_literal:e \tex_special:D
+\cs_new_protected:Npn \__kernel_backend_literal:n #1
+ { \__kernel_backend_literal:e { \exp_not:n {#1} } }
+\cs_generate_variant:Nn \__kernel_backend_literal:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{\texttt{dvips} backend}
+%
+% \begin{macrocode}
+%<*dvips>
+% \end{macrocode}
+%
+% \begin{macro}
+% {\__kernel_backend_literal_postscript:n, \__kernel_backend_literal_postscript:x}
+% Literal PostScript can be included using a few low-level formats. Here,
+% we use the form with no positioning: this is overall more convenient as
+% a wrapper. Note that this does require that where position is important,
+% an appropriate wrapper is included.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_literal_postscript:n #1
+ { \__kernel_backend_literal:n { ps:: #1 } }
+\cs_generate_variant:Nn \__kernel_backend_literal_postscript:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_postscript:n, \__kernel_backend_postscript:x}
+% PostScript data that does have positioning, and also applying
+% a shift to |SDict| (which is not done automatically by
+% |ps:| or |ps::|, in contrast to |!| or |"|).
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_postscript:n #1
+ { \__kernel_backend_literal:n { ps: SDict ~ begin ~ #1 ~ end } }
+\cs_generate_variant:Nn \__kernel_backend_postscript:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_postscript_header:n}
+% PostScript for the header: a small saving but makes the code clearer.
+% This is held until the start of shipout such that a document with no
+% actual output does not write anything.
+% \begin{macrocode}
+\cs_new_protected:Npx \__kernel_backend_postscript_header:n #1
+%<*initex>
+ { \__kernel_backend_literal:n { ! #1 } }
+%</initex>
+%<*package>
+ {
+ \cs_if_exist:NTF \AtBeginDvi
+ { \exp_not:N \AtBeginDvi }
+ { \use:n }
+ { \__kernel_backend_literal:n { ! #1 } }
+ }
+%</package>
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}
+% {
+% \__kernel_backend_align_begin:,
+% \__kernel_backend_align_end:
+% }
+% In \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. Notice that the |[begin]|/^^A
+% |[end]| pair here mean that we can use a run of PostScript statements
+% in separate lines: not \emph{required} but does make the code and
+% output more clear.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_align_begin:
+ {
+ \__kernel_backend_literal:n { ps::[begin] }
+ \__kernel_backend_literal_postscript:n { currentpoint }
+ \__kernel_backend_literal_postscript:n { currentpoint~translate }
+ }
+\cs_new_protected:Npn \__kernel_backend_align_end:
+ {
+ \__kernel_backend_literal_postscript:n { neg~exch~neg~exch~translate }
+ \__kernel_backend_literal:n { ps::[end] }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_scope_begin:, \__kernel_backend_scope_end:}
+% Saving/restoring scope for general operations needs to be done with
+% \texttt{dvips} positioning (try without to see this!). Thus we need the
+% |ps:| version of the special here. As only the graphics state is ever
+% altered within this pairing, we use the lower-cost |g|-versions.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_scope_begin:
+ { \__kernel_backend_literal:n { ps:gsave } }
+\cs_new_protected:Npn \__kernel_backend_scope_end:
+ { \__kernel_backend_literal:n { ps:grestore } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</dvips>
+% \end{macrocode}
+%
+% \subsection{\texttt{pdfmode} backend}
+%
+% \begin{macrocode}
+%<*pdfmode>
+% \end{macrocode}
+%
+% The direct PDF backend covers both \pdfTeX{} and \LuaTeX{}. The latter
+% renames and restructures the backend primitives but this can be handled
+% at one level of abstraction. As such, we avoid using two separate backends
+% for this material at the cost of some \texttt{x}-type definitions to get
+% everything expanded up-front.
+%
+% \begin{macro}{\__kernel_backend_literal_pdf:n, \__kernel_backend_literal_pdf:x}
+% 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 \__kernel_backend_literal_pdf:n #1
+ {
+ \cs_if_exist:NTF \tex_pdfextension:D
+ { \tex_pdfextension:D literal }
+ { \tex_pdfliteral:D }
+ { \exp_not:N \exp_not:n {#1} }
+ }
+\cs_generate_variant:Nn \__kernel_backend_literal_pdf:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_literal_page:n}
+% Page literals are pretty simple. To avoid an expansion, we write out
+% by hand.
+% \begin{macrocode}
+\cs_new_protected:Npx \__kernel_backend_literal_page:n #1
+ {
+ \cs_if_exist:NTF \tex_pdfextension:D
+ { \tex_pdfextension:D literal ~ }
+ { \tex_pdfliteral:D }
+ page
+ { \exp_not:N \exp_not:n {#1} }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_scope_begin:, \__kernel_backend_scope_end:}
+% Higher-level interfaces for saving and restoring the graphic state.
+% \begin{macrocode}
+\cs_new_protected:Npx \__kernel_backend_scope_begin:
+ {
+ \cs_if_exist:NTF \tex_pdfextension:D
+ { \tex_pdfextension:D save \scan_stop: }
+ { \tex_pdfsave:D }
+ }
+\cs_new_protected:Npx \__kernel_backend_scope_end:
+ {
+ \cs_if_exist:NTF \tex_pdfextension:D
+ { \tex_pdfextension:D restore \scan_stop: }
+ { \tex_pdfrestore:D }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_matrix:n, \__kernel_backend_matrix:x}
+% 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 \__kernel_backend_matrix:n #1
+ {
+ \cs_if_exist:NTF \tex_pdfextension:D
+ { \tex_pdfextension:D setmatrix }
+ { \tex_pdfsetmatrix:D }
+ { \exp_not:N \exp_not:n {#1} }
+ }
+\cs_generate_variant:Nn \__kernel_backend_matrix:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</pdfmode>
+% \end{macrocode}
+%
+% \subsection{\texttt{dvipdfmx} backend}
+%
+% \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 backends, with some \texttt{clean up} for \texttt{xdvipdfmx} as
+% required.
+%
+% \begin{macro}{\__kernel_backend_literal_pdf:n, \__kernel_backend_literal_pdf:x}
+% Equivalent to \texttt{pdf:content} but favored as the link to
+% the \pdfTeX{} primitive approach is clearer.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_literal_pdf:n #1
+ { \__kernel_backend_literal:n { pdf:literal~ #1 } }
+\cs_generate_variant:Nn \__kernel_backend_literal_pdf:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_literal_page:n}
+% Whilst the manual says this is like |literal direct| in \pdfTeX{},
+% it closes the |BT| block!
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_literal_page:n #1
+ { \__kernel_backend_literal:n { pdf:literal~direct~ #1 } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_scope_begin:, \__kernel_backend_scope_end:}
+% Scoping is done using the backend-specific specials.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_scope_begin:
+ { \__kernel_backend_literal:n { x:gsave } }
+\cs_new_protected:Npn \__kernel_backend_scope_end:
+ { \__kernel_backend_literal:n { x:grestore } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</dvipdfmx|xdvipdfmx>
+% \end{macrocode}
+%
+% \subsection{\texttt{dvisvgm} backend}
+%
+% \begin{macrocode}
+%<*dvisvgm>
+% \end{macrocode}
+%
+% \begin{macro}{\__kernel_backend_literal_svg:n, \__kernel_backend_literal_svg:x}
+% Unlike the other backends, the requirements for making SVG files mean
+% that we can't conveniently transform all operations to the current point.
+% That makes life a bit more tricky later as that needs to be accounted for.
+% A new line is added after each call to help to keep the output readable
+% for debugging.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_literal_svg:n #1
+ { \__kernel_backend_literal:n { dvisvgm:raw~ #1 { ?nl } } }
+\cs_generate_variant:Nn \__kernel_backend_literal_svg:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_scope_begin:, \__kernel_backend_scope_end:}
+% A scope in SVG terms is slightly different to the other backends as
+% operations have to be \enquote{tied} to these not simply inside them.
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_scope_begin:
+ { \__kernel_backend_literal_svg:n { <g> } }
+\cs_new_protected:Npn \__kernel_backend_scope_end:
+ { \__kernel_backend_literal_svg:n { </g> } }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macro}{\__kernel_backend_scope_begin:n, \__kernel_backend_scope_begin:x}
+% In SVG transformations, clips and so on are attached directly to scopes so
+% we need a way or allowing for that. This is rather more useful than
+% \cs{__kernel_backend_scope_begin:} as a result.
+% No assumptions are made about the nature
+% of the scoped operation(s).
+% \begin{macrocode}
+\cs_new_protected:Npn \__kernel_backend_scope_begin:n #1
+ { \__kernel_backend_literal_svg:n { <g~ #1 > } }
+\cs_generate_variant:Nn \__kernel_backend_scope_begin:n { x }
+% \end{macrocode}
+% \end{macro}
+%
+% \begin{macrocode}
+%</dvisvgm>
+% \end{macrocode}
+%
+% \begin{macrocode}
+%</initex|package>
+% \end{macrocode}
+%
+% \end{implementation}
+%
+% \PrintIndex