diff options
Diffstat (limited to 'Master/texmf-dist/source/latex-dev/l3backend/l3backend-basics.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex-dev/l3backend/l3backend-basics.dtx | 497 |
1 files changed, 497 insertions, 0 deletions
diff --git a/Master/texmf-dist/source/latex-dev/l3backend/l3backend-basics.dtx b/Master/texmf-dist/source/latex-dev/l3backend/l3backend-basics.dtx new file mode 100644 index 00000000000..fbac5033179 --- /dev/null +++ b/Master/texmf-dist/source/latex-dev/l3backend/l3backend-basics.dtx @@ -0,0 +1,497 @@ +% \iffalse meta-comment +% +%% File: l3backend-basics.dtx +% +% Copyright (C) 2019-2024 The LaTeX 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 \pkg{l3backend-basics} module\\ Backend basics^^A +% } +% +% \author{^^A +% The \LaTeX{} Project\thanks +% {^^A +% E-mail: +% \href{mailto:latex-team@latex-project.org} +% {latex-team@latex-project.org}^^A +% }^^A +% } +% +% \date{Released 2024-04-11} +% +% \maketitle +% +% \begin{documentation} +% +% \end{documentation} +% +% \begin{implementation} +% +% \section{\pkg{l3backend-basics} implementation} +% +% \begin{macrocode} +%<*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-backend 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} +\ProvidesExplFile +%<*dvipdfmx> + {l3backend-dvipdfmx.def}{2024-04-11}{} + {L3 backend support: dvipdfmx} +%</dvipdfmx> +%<*dvips> + {l3backend-dvips.def}{2024-04-11}{} + {L3 backend support: dvips} +%</dvips> +%<*dvisvgm> + {l3backend-dvisvgm.def}{2024-04-11}{} + {L3 backend support: dvisvgm} +%</dvisvgm> +%<*luatex> + {l3backend-luatex.def}{2024-04-11}{} + {L3 backend support: PDF output (LuaTeX)} +%</luatex> +%<*pdftex> + {l3backend-pdftex.def}{2024-04-11}{} + {L3 backend support: PDF output (pdfTeX)} +%</pdftex> +%<*xetex> + {l3backend-xetex.def}{2024-04-11}{} + {L3 backend support: XeTeX} +%</xetex> +% \end{macrocode} +% +% Check if the loaded kernel is at least enough to load this file. +% The kernel date has to be at least equal to \cs{ExplBackendFileDate} +% or later. If \cs{__kernel_dependency_version_check:Nn} doesn't +% exist we're loading in an older kernel, so it's an error anyway. +% With time, this test should vanish and only the dependency check +% should remain. +% \begin{macrocode} +\cs_if_exist:NTF \__kernel_dependency_version_check:nn + { + \__kernel_dependency_version_check:nn {2023-10-10} +%<dvipdfmx> {l3backend-dvipdfmx.def} +%<dvips> {l3backend-dvips.def} +%<dvisvgm> {l3backend-dvisvgm.def} +%<luatex> {l3backend-luatex.def} +%<pdftex> {l3backend-pdftex.def} +%<xetex> {l3backend-xetex.def} + } + { + \cs_if_exist_use:cF { @latex@error } { \errmessage } + { + Mismatched~LaTeX~support~files~detected. \MessageBreak + Loading~aborted! + } + { \use:c { @ehd } } + \tex_endinput:D + } +% \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 \LuaTeX{}/pdfTeX{}-like. +% \item \LuaTeX{}/pdfTeX{} and \texttt{dvipdfmx}/\XeTeX{} share drawing routines. +% \item \XeTeX{} is the same as \texttt{dvipdfmx} other than image size +% extraction so takes most of the same code. +% \end{itemize} +% +% \begin{macro} +% { +% \__kernel_backend_literal:e, +% \__kernel_backend_literal:n +% } +% 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} } } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__kernel_backend_first_shipout:n} +% We need to write at first shipout in a few places. As we want to use the +% most up-to-date method, +% \begin{macrocode} +\cs_if_exist:NTF \@ifl@t@r + { + \@ifl@t@r \fmtversion { 2020-10-01 } + { + \cs_new_protected:Npn \__kernel_backend_first_shipout:n #1 + { \hook_gput_code:nnn { shipout / firstpage } { l3backend } {#1} } + } + { \cs_new_eq:NN \__kernel_backend_first_shipout:n \AtBeginDvi } + } + { \cs_new_eq:NN \__kernel_backend_first_shipout:n \use:n } +% \end{macrocode} +% \end{macro} +% +% \subsection{\texttt{dvips} backend} +% +% \begin{macrocode} +%<*dvips> +% \end{macrocode} +% +% \begin{macro} +% {\__kernel_backend_literal_postscript:n, \__kernel_backend_literal_postscript:e} +% 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 { e } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__kernel_backend_postscript:n, \__kernel_backend_postscript:e} +% 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 { e } +% \end{macrocode} +% \end{macro} +% +% 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} +\bool_if:NT \g__kernel_backend_header_bool + { + \__kernel_backend_first_shipout:n + { \__kernel_backend_literal:n { header = l3backend-dvips.pro } } + } +% \end{macrocode} +% +% \begin{macro} +% { +% \__kernel_backend_align_begin:, +% \__kernel_backend_align_end: +% } +% In \texttt{dvips} there is no built-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{\LuaTeX{} and \pdfTeX{} backends} +% +% \begin{macrocode} +%<*luatex|pdftex> +% \end{macrocode} +% +% Both \LuaTeX{} and \pdfTeX{} write PDFs directly rather than via an +% intermediate file. Although there are similarities, the move of \LuaTeX{} +% to have more code in Lua means we create two independent files using +% shared DocStrip code. +% +% \begin{macro}{\__kernel_backend_literal_pdf:n, \__kernel_backend_literal_pdf:e} +% 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:Npn \__kernel_backend_literal_pdf:n #1 + { +%<*luatex> + \tex_pdfextension:D literal +%</luatex> +%<*pdftex> + \tex_pdfliteral:D +%</pdftex> + { \exp_not:n {#1} } + } +\cs_generate_variant:Nn \__kernel_backend_literal_pdf:n { e } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__kernel_backend_literal_page:n, \__kernel_backend_literal_page:e} +% Page literals are pretty simple. To avoid an expansion, we write out +% by hand. +% \begin{macrocode} +\cs_new_protected:Npn \__kernel_backend_literal_page:n #1 + { +%<*luatex> + \tex_pdfextension:D literal ~ +%</luatex> +%<*pdftex> + \tex_pdfliteral:D +%</pdftex> + page { \exp_not:n {#1} } + } +\cs_new_protected:Npn \__kernel_backend_literal_page:e #1 + { +%<*luatex> + \tex_pdfextension:D literal ~ +%</luatex> +%<*pdftex> + \tex_pdfliteral:D +%</pdftex> + page {#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:Npn \__kernel_backend_scope_begin: + { +%<*luatex> + \tex_pdfextension:D save \scan_stop: +%</luatex> +%<*pdftex> + \tex_pdfsave:D +%</pdftex> + } +\cs_new_protected:Npn \__kernel_backend_scope_end: + { +%<*luatex> + \tex_pdfextension:D restore \scan_stop: +%</luatex> +%<*pdftex> + \tex_pdfrestore:D +%</pdftex> + } +% \end{macrocode} +% \end{macro} +% +% \begin{macro}{\__kernel_backend_matrix:n, \__kernel_backend_matrix:e} +% 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:Npn \__kernel_backend_matrix:n #1 + { +%<*luatex> + \tex_pdfextension:D setmatrix +%</luatex> +%<*pdftex> + \tex_pdfsetmatrix:D +%</pdftex> + { \exp_not:n {#1} } + } +\cs_generate_variant:Nn \__kernel_backend_matrix:n { e } +% \end{macrocode} +% \end{macro} +% +% \begin{macrocode} +%</luatex|pdftex> +% \end{macrocode} +% +% \subsection{\texttt{dvipdfmx} backend} +% +% \begin{macrocode} +%<*dvipdfmx|xetex> +% \end{macrocode} +% +% The \texttt{dvipdfmx} shares code with the PDF mode one (using the common +% section to this file) but also with \XeTeX{}. 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 \XeTeX{} as +% required. +% +% \begin{macro}{\__kernel_backend_literal_pdf:n, \__kernel_backend_literal_pdf:e} +% Undocumented but equivalent to \pdfTeX{}'s |literal| keyword. It's similar to +% be not the same as the documented |contents| keyword as that adds a |q|/|Q| +% pair. +% \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 { e } +% \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. We use the versions +% originally from \texttt{xdvidfpmx} (\texttt{x:}) as these are well-tested +% \enquote{in the wild}. +% \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|xetex> +% \end{macrocode} +% +% \subsection{\texttt{dvisvgm} backend} +% +% \begin{macrocode} +%<*dvisvgm> +% \end{macrocode} +% +% \begin{macro}{\__kernel_backend_literal_svg:n, \__kernel_backend_literal_svg:e} +% 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 { e } +% \end{macrocode} +% \end{macro} +% +% \begin{variable}{\g__kernel_backend_scope_int, \l__kernel_backend_scope_int} +% In SVG, we need to track scope nesting as properties attach to scopes; that +% requires a pair of \texttt{int} registers. +% \begin{macrocode} +\int_new:N \g__kernel_backend_scope_int +\int_new:N \l__kernel_backend_scope_int +% \end{macrocode} +% \end{variable} +% +% \begin{macro}{\__kernel_backend_scope_begin:, \__kernel_backend_scope_end:} +% \begin{macro}{\__kernel_backend_scope_begin:n, \__kernel_backend_scope_begin:e} +% \begin{macro}{\__kernel_backend_scope:n, \__kernel_backend_scope:e} +% In SVG, the need to attach concepts to a scope means we need to be sure we +% will close all of the open scopes. That is easiest done if we only need +% an outer \enquote{wrapper} \texttt{begin}/\texttt{end} pair, and within +% that we apply operations as a simple scoped statements. To keep down the +% non-productive groups, we also have a \texttt{begin} version that does take +% an argument. +% \begin{macrocode} +\cs_new_protected:Npn \__kernel_backend_scope_begin: + { + \__kernel_backend_literal_svg:n { <g> } + \int_set_eq:NN + \l__kernel_backend_scope_int + \g__kernel_backend_scope_int + \group_begin: + \int_gset:Nn \g__kernel_backend_scope_int { 1 } + } +\cs_new_protected:Npn \__kernel_backend_scope_end: + { + \prg_replicate:nn + { \g__kernel_backend_scope_int } + { \__kernel_backend_literal_svg:n { </g> } } + \group_end: + \int_gset_eq:NN + \g__kernel_backend_scope_int + \l__kernel_backend_scope_int + } +\cs_new_protected:Npn \__kernel_backend_scope_begin:n #1 + { + \__kernel_backend_literal_svg:n { <g ~ #1 > } + \int_set_eq:NN + \l__kernel_backend_scope_int + \g__kernel_backend_scope_int + \group_begin: + \int_gset:Nn \g__kernel_backend_scope_int { 1 } + } +\cs_generate_variant:Nn \__kernel_backend_scope_begin:n { e } +\cs_new_protected:Npn \__kernel_backend_scope:n #1 + { + \__kernel_backend_literal_svg:n { <g ~ #1 > } + \int_gincr:N \g__kernel_backend_scope_int + } +\cs_generate_variant:Nn \__kernel_backend_scope:n { e } +% \end{macrocode} +% \end{macro} +% \end{macro} +% \end{macro} +% +% \begin{macrocode} +%</dvisvgm> +% \end{macrocode} +% +% \begin{macrocode} +%</package> +% \end{macrocode} +% +% \end{implementation} +% +% \PrintIndex |