% \iffalse meta-comment
%
%% File: xcoffins.dtx
%
% Copyright (C) 2010-2026 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 "l3experimental 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]{l3doc}
\usepackage{xcoffins} % Not yet part of expl3, so not in l3doc
\usepackage{xcolor} % As coffins only loads basic color support
\NewCoffin \ExampleCoffin
\NewCoffin \SmallCoffin
\NewCoffin \OutputCoffin
\NewCoffin \RedCoffin
\NewCoffin \BlueCoffin
\NewCoffin \GreenCoffin
\NewCoffin \YellowCoffin
\NewCoffin \OrangeCoffin
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
%
% \title{^^A
%   The \pkg{xcoffins} package\\ Design-level coffins^^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 2026-05-15}
%
% \maketitle
%
% \begin{documentation}
%
% \section{Introduction: the coffin concept}
%
% In \LaTeX3 terminology, a \enquote{coffin} is a box containing
% typeset material. Along with the box itself, the coffin structure
% includes information on the size and shape of the box, which makes
% it possible to align two or more coffins easily. This is achieved
% by providing a series of `poles' for each coffin. These
% are horizontal and vertical lines through the coffin at defined
% positions, for example the top or horizontal center. The points
% where these poles intersect are called \enquote{handles}. Two
% coffins can then be aligned by describing the relationship between
% a handle on one coffin with a handle on the second. In words, an
% example might then read
% \begin{quote}
%   Align the top-left handle of coffin A with the bottom-right
%   handle of coffin B.
% \end{quote}
%
% The locations of coffin handles are much easier to understand
% visually. Figure~\ref{fgr:handles} shows the standard handle
% positions for a coffin typeset in horizontal mode (left) and in
% vertical mode (right). Notice that the later case results in a greater
% number of handles being available. As illustrated, each handle
% results from the intersection of two poles. For example, the center
% of the coffin is marked |(hc,vc)|, i.e., it is the
% point of intersection of the horizontal center pole with the
% vertical center pole. New handles are generated automatically when
% poles are added to a coffin: handles are \enquote{dynamic} entities.
%
% \begin{figure}
%   \hfil
%   \begin{minipage}{0.4\textwidth}
%     \SetHorizontalCoffin\ExampleCoffin
%       {\color{black!10!white}\rule{1 in}{1 in}}
%     \DisplayCoffinHandles\ExampleCoffin{blue}
%   \end{minipage}
%   \hfil
%   \begin{minipage}{0.4\textwidth}
%     \SetVerticalCoffin\ExampleCoffin{1 in}
%       {\color{black!10!white}\rule{1 in}{1 in}}
%     \DisplayCoffinHandles\ExampleCoffin{blue}
%   \end{minipage}
%   \hfil
%   \caption{Standard coffin handles: left, horizontal coffin; right,
%     vertical coffin}
%   \label{fgr:handles}
% \end{figure}
%
%\section{Creating and setting coffins}
%
% Before any alignment can take place, coffins must be created and
% their contents must be created. All coffin operations are local
% to the current \TeX{} group with the exception of coffin creation.
% \begin{function}{\NewCoffin}
%   \begin{syntax}
%     \cs{NewCoffin} \meta{coffin}
%   \end{syntax}
%   Before a \meta{coffin} can be used, it must be allocated using
%   \cs{NewCoffin}. The name of the \meta{coffin} should be a
%   control sequence (starting with the escape character, usually
%   |\|), for example
%   \begin{verbatim}
%     \NewCoffin\MyCoffin
%   \end{verbatim}
%   Coffins are allocated globally, and an error will be raised if the
%   name of the \meta{coffin} is not globally-unique.
% \end{function}
%
% \begin{function}{\SetHorizontalCoffin}
%   \begin{syntax}
%     \cs{SetHorizontalCoffin} \meta{coffin} \Arg{material}
%   \end{syntax}
%   Typesets the \meta{material} in horizontal mode, storing the result
%   in the \meta{coffin}. The standard poles for the \meta{coffin} are
%   then set up based on the size of the typeset material.
% \end{function}
%
% \begin{function}{\SetVerticalCoffin}
%   \begin{syntax}
%     \cs{SetVerticalCoffin} \meta{coffin} \Arg{width} \Arg{material}
%   \end{syntax}
%   Typesets the \meta{material} in vertical mode constrained to the
%   given \meta{width} and stores the result in the \meta{coffin}. The
%   standard poles for the \meta{coffin} are then set up based on the
%   size of the typeset material.
% \end{function}
%
% \section{Controlling coffin poles}
%
% A number of standard poles are automatically generated when the coffin
% is set or an alignment takes place. The standard poles for all coffins
% are:
% \begin{itemize}[font = \ttfamily]
%   \item[l] a pole running along the left-hand edge of the bounding
%     box of the coffin;
%   \item[hc] a pole running vertically through the center of the coffin
%     half-way between the left- and right-hand edges of the bounding
%       box (i.e., the \enquote{horizontal center});
%   \item[r] a pole running along the right-hand edge of the bounding
%     box of the coffin;
%   \item[b] a pole running along the bottom edge of the bounding
%     box of the coffin;
%   \item[vc] a pole running horizontally through the center of the
%     coffin half-way between the bottom and top edges of the bounding
%     box (i.e., the \enquote{vertical center});
%   \item[t] a pole running along the top edge of the bounding
%     box of the coffin;
%   \item[H] a pole running along the baseline of the typeset material
%     contained in the coffin.
% \end{itemize}
% In addition, coffins containing vertical-mode material also
% feature poles which reflect the richer nature of these systems:
% \begin{itemize}
%   \item[B] a pole running along the baseline of the material at the
%     bottom of the coffin.
%   \item[T] a pole running along the baseline of the material at the top
%     of the coffin.
% \end{itemize}
%
% \begin{function}{\SetHorizontalPole}
%   \begin{syntax}
%     \cs{SetHorizontalPole} \meta{coffin} \Arg{pole} \Arg{offset}
%   \end{syntax}
%   Sets the \meta{pole} to run horizontally through the \meta{coffin}.
%   The \meta{pole} will be located at the \meta{offset} from the
%   baseline of the \meta{coffin}. The
%   \meta{offset} should be given as a dimension expression; this may
%   include the terms \cs{TotalHeight}, \cs{Height}, \cs{Depth} and
%   \cs{Width}, which will evaluate to the appropriate dimensions of
%   the \meta{coffin}. For example, to create a pole running
%   horizontally through the coffin at one third of the distance from
%   the base of the coffin to the top, the appropriate instruction would
%   be
%   \begin{verbatim}
%     \SetHorizontalPole \MyCoffin {height/3} {\TotalHeight/3}
%   \end{verbatim}
%   Note that poles which run \emph{horizontally} are described in terms
%   of their \emph{vertical} location in the coffin. Also notice that
%   the total height of the coffin is described by the sum of
%   \cs{Height} and \cs{Depth}: these are both measured from the
%   horizontal baseline of the material in the coffin.
% \end{function}
%
% \begin{function}{\SetVerticalPole}
%   \begin{syntax}
%     \cs{SetVerticalPole} \meta{coffin} \Arg{pole} \Arg{offset}
%   \end{syntax}
%   Sets the \meta{pole} to run vertically through the \meta{coffin}.
%   The \meta{pole} will be located at the \meta{offset} from the
%   left-hand edge of the bounding box of the \meta{coffin}. The
%   \meta{offset} should be given as a dimension expression; this may
%   include the terms \cs{TotalHeight}, \cs{Height}, \cs{Depth} and
%   \cs{Width}, which will evaluate to the appropriate dimensions of
%   the \meta{coffin}. For example, to create a pole running vertically
%   through the coffin at one third of the distance from the left-hand
%   edge, the appropriate instruction would be
%   \begin{verbatim}
%     \SetVerticalPole \MyCoffin {width/3} {\Width/3}
%   \end{verbatim}
%   Note that poles which run \emph{vertically} are described in terms
%   of their \emph{horizontal} location in the coffin.
% \end{function}
%
% \begin{function}{\TotalHeight}
%   \begin{syntax}
%     \cs{TotalHeight}
%   \end{syntax}
%   Within the \meta{offset} argument of \cs{SetHorizontalPole} and
%   \cs{SetVerticalPole}, \cs{TotalHeight} will give the distance from
%   the base to the top of the bounding box of the relevant coffin.
% \end{function}
%
% \begin{function}{\Height}
%   \begin{syntax}
%     \cs{Height}
%   \end{syntax}
%   Within the \meta{offset} argument of \cs{SetHorizontalPole} and
%   \cs{SetVerticalPole}, \cs{Height} will give the distance from the
%   baseline to the top of the bounding box of the relevant coffin.
% \end{function}
%
% \begin{function}{\Depth}
%   \begin{syntax}
%     \cs{Depth}
%   \end{syntax}
%   Within the \meta{offset} argument of \cs{SetHorizontalPole} and
%   \cs{SetVerticalPole}, \cs{Depth} will give the distance from the
%   baseline to the bottom of the bounding box of the relevant coffin.
% \end{function}
%
% \begin{function}{\Width}
%   \begin{syntax}
%     \cs{Width}
%   \end{syntax}
%   Within the \meta{offset} argument of \cs{SetHorizontalPole} and
%   \cs{SetVerticalPole}, \cs{Width} will give the distance from the
%   right edge to the left edge of the bounding box of the relevant
%   coffin.
% \end{function}
%
% \section{Rotating coffins}
%
% \begin{function}{\RotateCoffin}
%   \begin{syntax}
%     \cs{RotateCoffin} \meta{coffin} \Arg{angle}
%   \end{syntax}
%   Rotates the \meta{coffin} by the given \meta{angle} about its reference
%   point (given in degrees counter-clockwise) . This process will rotate both
%   the coffin content and poles. Multiple rotations will not result in
%   the bounding box of the coffin growing unnecessarily.
%
%   The effect of rotation on a coffin is illustrated in
%   Figure~\ref{fgr:rotation}. As is shown, the coffin handles will
%   remain correctly positioned relative to the content of the coffin.
%   The \enquote{top} of a rotated coffin may of course no longer be the
%   edge closest to the top of the physical page.
% \end{function}
%
%   \begin{figure}
%     \hfil
%     \SetHorizontalCoffin\ExampleCoffin
%       {^^A
%         \color{black!10!white}\rule{0.5 in}{1 in}^^A
%         \color{black!20!white}\rule{0.5 in}{1 in}^^A
%       }
%     \begin{minipage}{0.4\textwidth}
%       \DisplayCoffinHandles\ExampleCoffin{blue}
%     \end{minipage}
%     \hfil
%     \begin{minipage}{0.4\textwidth}
%       \RotateCoffin\ExampleCoffin{45}
%       \DisplayCoffinHandles\ExampleCoffin{blue}
%     \end{minipage}
%     \hfil
%     \caption{Coffin rotation: left, unrotated; right, rotated by
%       $45$\textdegree.}
%     \label{fgr:rotation}
%   \end{figure}
%
% \section{Resizing coffins}
%
% \begin{function}{\ResizeCoffin}
%   \begin{syntax}
%     \cs{ResizeCoffin} \meta{coffin} \Arg{width} \Arg{total-height}
%   \end{syntax}
%   Resized the \meta{coffin} to \meta{width} and \meta{total-height},
%   both of which should be given as dimension expressions.
% \end{function}
%
% \begin{function}{\ScaleCoffin}
%   \begin{syntax}
%     \cs{ScaleCoffin} \meta{coffin} \Arg{x-scale} \Arg{y-scale}
%   \end{syntax}
%   Scales the \meta{coffin} by a factors \meta{x-scale} and
%   \meta{y-scale} in the horizontal and vertical directions,
%   respectively. The two scale factors should be given as real numbers.
% \end{function}
%
% \cs{ResizeCoffin} and \cs{ScaleCoffin} can be used interchangeably:
% whether scale factors or absolute values are the best form for the
% resizing will depend upon the context (Figure~\ref{fgr:resizing}).
%
% \begin{figure}
%   \hfil
%   \SetHorizontalCoffin\ExampleCoffin
%     {^^A
%       \color{black!10!white}\rule{0.5 in}{1 in}^^A
%       \color{black!20!white}\rule{0.5 in}{1 in}^^A
%     }
%   \begin{minipage}{0.4\textwidth}
%     \ResizeCoffin \ExampleCoffin {4 cm} {3 cm}
%     \DisplayCoffinHandles \ExampleCoffin {blue}
%   \end{minipage}
%   \hfil
%   \begin{minipage}{0.4\textwidth}
%     \ScaleCoffin \ExampleCoffin {2.0} {0.5}
%     \DisplayCoffinHandles \ExampleCoffin {blue}
%   \end{minipage}
%   \hfil
%   \caption{Coffin resizing: left, resized to exactly $4$\,cm by
%   $6$\,cm; right, scaled a factors of $2$ and $0.5$ in
%   $x$ and $y$, respectively (example coffin as in
%   Figure~\ref{fgr:rotation}).}
%   \label{fgr:resizing}
% \end{figure}
%
% \section{Joining coffins}
%
% The key operation for coffins is joining coffins to each other. This
% is always carried out such that the first coffin is the
% \enquote{parent}, and is updated by the alignment. The second
% \enquote{child} coffin is not altered by the alignment process.
%
% \begin{function}{\JoinCoffins}
%   \begin{syntax}
%     \cs{JoinCoffins} *
%     ~~\meta{coffin1} [ \meta{coffin1-pole1} , \meta{coffin1-pole2} ]
%     ~~\meta{coffin2} [ \meta{coffin2-pole1} , \meta{coffin2-pole2} ]
%     ~~( \meta{x-offset} , \meta{y-offset} )
%   \end{syntax}
%   Joining of two coffins is carried out by the \cs{JoinCoffins}
%   function, which takes two mandatory arguments: the \enquote{parent}
%   \meta{coffin1} and the \enquote{child} \meta{coffin2}. All of the
%   other arguments shown are optional.
% \end{function}
%
%   The standard \cs{JoinCoffins} functions joins \meta{coffin2} to
%   \meta{coffin1} such that the bounding box of \meta{coffin1} after the
%   process will expand. The new bounding box will be the smallest
%   rectangle covering the bounding boxes of the two input coffins.
%   When the starred variant of \cs{JoinCoffins} is used, the bounding
%   box of \meta{coffin1} is not altered, i.e., \meta{coffin2} may
%   protrude outside of the bounding box of the updated \meta{coffin1}.
%   The difference between the two forms of alignment is best illustrated
%   using a visual example. In Figure~\ref{fgr:alignment}, the two
%   processes are contrasted. In both cases, the small red coffin has been
%   aligned with the large grey coffin. In the left-hand illustration,
%   the \cs{JoinCoffins} function was used, resulting in an expanded
%   bounding box. In contrast, on the right \cs{JoinCoffins}|*| was used,
%   meaning that the bounding box does not include the area of the
%   smaller coffin.
%
%   \begin{figure}
%     \fboxsep 0 pt\relax
%     \SetHorizontalCoffin\ExampleCoffin
%       {\color{black!20!white}\rule{1 in}{1 in}}
%     \SetHorizontalCoffin \SmallCoffin
%       {\color{red!20!white}\rule{0.1 in}{0.1 in}}
%     \hfil
%     \begin{minipage}{0.4\textwidth}
%       \centering
%       \JoinCoffins\ExampleCoffin[vc,r]\SmallCoffin[vc,l]
%       \fbox{\TypesetCoffin\ExampleCoffin}
%     \end{minipage}
%     \hfil
%     \begin{minipage}{0.4\textwidth}
%       \centering
%        \JoinCoffins*\ExampleCoffin[vc,r]\SmallCoffin[vc,l]
%       \fbox{\TypesetCoffin\ExampleCoffin}%
%     \end{minipage}
%     \hfil
%     \caption{Contrast between \cs{JoinCoffins} (left) and
%       \cs{JoinCoffins*} (right); the bounding box of the coffin is show
%       in black.}
%     \label{fgr:alignment}
%   \end{figure}
%
%   The alignment is carried out by first calculating \meta{handle1}, the
%   point of intersection of \meta{coffin1-pole1} and
%   \meta{coffin1-pole2}, and \meta{handle2}, the point of intersection
%   of \meta{coffin2-pole1} and \meta{coffin2-pole2}. If the two
%   \meta{poles} are not specified, \cs{JoinCoffins} will use the
%   default value |(H,l)|, i.e., the reference point used by \TeX\
%   for the underlying box. Once the two \meta{handles} have been
%   located, \meta{coffin2} is then attached to \meta{coffin1} such that
%   the relationship between \meta{handle1} and \meta{handle2} is
%   described by the \meta{x-offset} and \meta{y-offset}. This
%   \meta{offset} is an optional argument, and if it is not given then
%   |(0 pt, 0 pt)| is used.
%
% Notice that when \cs{JoinCoffins} is used the new bounding box is
% the smallest rectangle containing the bounding boxes of the two input
% coffins. As a result, it will include additional white space unless
% one coffin entirely overlaps the other (Figure~\ref{fgr:bounding},
% left). Rotation of coffins will take account of the extent of the
% material after rotation when re-calculating the bounding box. This
% means that no \emph{unnecessary} white space will be added on
% rotation (Figure~\ref{fgr:bounding}, right).
%
% \begin{figure}
%   \fboxsep 0 pt\relax
%   \SetHorizontalCoffin\ExampleCoffin
%     {\color{black!20!white}\rule{1 in}{1 in}}
%   \SetHorizontalCoffin\SmallCoffin
%     {\color{red!20!white}\rule{0.1 in}{0.1 in}}
%   \JoinCoffins\ExampleCoffin[vc,r]\SmallCoffin[vc,l]
%   \hfil
%   \begin{minipage}{0.4\textwidth}
%     \centering
%     \fbox{\copy\ExampleCoffin}
%   \end{minipage}
%   \hfil
%   \begin{minipage}{0.4\textwidth}
%     \centering
%     \RotateCoffin\ExampleCoffin{135}
%     \fbox{\copy\ExampleCoffin}
%   \end{minipage}
%   \hfil
%   \caption{The effect of rotation of a joined coffin: the black line
%     shows the coffin bounding box.}
%   \label{fgr:bounding}
% \end{figure}
%
% As part of the joining procedure, the poles of the two input coffins
% are preserved within the structure of the updated coffin. In this way
% it is possible to carry out complex alignment procedures. The poles of
% a coffin after alignment may therefore be divided into three groups:
% \begin{enumerate}
%   \item The \enquote{native} poles of the updated coffin, such as
%     \texttt{l}, \texttt{r}, \texttt{hc}, \emph{etc}.
%   \item Poles derived from \meta{coffin1}, such as
%     \texttt{\meta{coffin1}-l},  \texttt{\meta{coffin1}-r},
%      \texttt{\meta{coffin1}-hc}, etc.
%   \item Poles derived from \meta{coffin2}, such as
%     \texttt{\meta{coffin2}-l},  \texttt{\meta{coffin2}-r},
%      \texttt{\meta{coffin2}-hc}, etc.
% \end{enumerate}
%
% Applying this ability allows a series of joining operations to
% take place, as illustrated in Figure~\ref{fgr:nested}. In this
% example, the scheme used for alignment was as follows:
% \begin{verbatim}
%   \SetHorizontalCoffin\OutputCoffin{}
%   \SetHorizontalCoffin\RedCoffin
%     {\color{red!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[vc,hc]\RedCoffin[vc,hc]
%   \SetHorizontalCoffin\BlueCoffin
%     {\color{blue!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[\RedCoffin-vc,\RedCoffin-hc]
%     \BlueCoffin[b,l]
%   \SetHorizontalCoffin\GreenCoffin
%     {\color{green!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[\BlueCoffin-vc,\BlueCoffin-hc]
%     \GreenCoffin[b,l]
%   \SetHorizontalCoffin\YellowCoffin
%     {\color{yellow!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[\GreenCoffin-vc,\GreenCoffin-hc]
%     \YellowCoffin[b,l]
%   \SetHorizontalCoffin \OrangeCoffin
%     {\color{orange!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[\BlueCoffin-t,\BlueCoffin-l]
%     \OrangeCoffin[b,r]
%   \TypesetCoffin\OutputCoffin
% \end{verbatim}
% This process begins by setting up \cs{OutputCoffin} to hold the joined
% output. Each join then takes place placing the new addition relative
% to the previous one. As each coffin joined has a unique name it is
% possible to align relative to each one of the component parts of the
% assembly. This is illustrated by the addition of the final
% \cs{OrangeCoffin} based on the earlier placement of the
% \cs{BlueCoffin}.
%
% \begin{figure}
%   \centering
%   \SetHorizontalCoffin\OutputCoffin{}
%   \SetHorizontalCoffin\RedCoffin
%     {\color{red!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[vc,hc]\RedCoffin[vc,hc]
%   \SetHorizontalCoffin\BlueCoffin
%     {\color{blue!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[\RedCoffin-vc,\RedCoffin-hc]
%     \BlueCoffin[b,l]
%   \SetHorizontalCoffin\GreenCoffin
%     {\color{green!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[\BlueCoffin-vc,\BlueCoffin-hc]
%     \GreenCoffin[b,l]
%   \SetHorizontalCoffin\YellowCoffin
%     {\color{yellow!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[\GreenCoffin-vc,\GreenCoffin-hc]
%     \YellowCoffin[b,l]
%   \SetHorizontalCoffin \OrangeCoffin
%     {\color{orange!20!white}\rule{0.2 in}{0.2 in}}
%   \JoinCoffins\OutputCoffin[\BlueCoffin-t,\BlueCoffin-l]
%     \OrangeCoffin[b,r]
%   \TypesetCoffin\OutputCoffin
%   \caption{Aligning coffins using poles from previous operations.}
%   \label{fgr:nested}
% \end{figure}
%
% \section{Typesetting coffins}
%
% \begin{function}{\TypesetCoffin}
%   \begin{syntax}
%     \cs{TypesetCoffin}
%     ~~\meta{coffin} [ \meta{pole1} , \meta{pole2} ]
%     ~~( \meta{x-offset} , \meta{y-offset} )
%   \end{syntax}
%   Typesetting is carried out by first calculating \meta{handle}, the
%   point of intersection of \meta{pole1} and \meta{pole2}. This is an
%   optional argument, and if not given then |(H,l)|, the \TeX{}
%   reference point of the underlying box, is used. The coffin
%   is then typeset such that the relationship between the current
%   reference point in the document and the \meta{handle} is described
%   by the \meta{x-offset} and \meta{y-offset}. This \meta{offset} is
%   optional, and if not given |(0 pt, 0 pt)| is used. Typesetting a
%   coffin is therefore analogous to carrying out an alignment where the
%   \enquote{parent} coffin is the current insertion point.
% \end{function}
%
% \section{Measuring coffins}
%
% There are places in the design process where it is useful to be able to
% measure coffins outside of pole-setting procedures.
%
% \begin{function}{\CoffinDepth}
%   \begin{syntax}
%     \cs{CoffinDepth} \meta{coffin}
%   \end{syntax}
%   Calculates the depth (below the baseline) of the \meta{coffin}
%   in a form suitable for use in a \meta{dimension expression}, for example
%   |\setlength{\mylength}{\CoffinDepth\ExampleCoffin}|.
% \end{function}
%
% \begin{function}{\CoffinHeight}
%   \begin{syntax}
%     \cs{CoffinHeight} \meta{coffin}
%   \end{syntax}
%   Calculates the height (above the baseline) of the \meta{coffin}
%   in a form suitable for use in a \meta{dimension expression}, for example
%   |\setlength{\mylength}{\CoffinHeight\ExampleCoffin}|.
% \end{function}
%
% \begin{function}{\CoffinTotalHeight}
%   \begin{syntax}
%     \cs{CoffinTotalHeight} \meta{coffin}
%   \end{syntax}
%   Calculates the total height of the \meta{coffin}
%   in a form suitable for use in a \meta{dimension expression}, for example
%   |\setlength{\mylength}{\CoffinTotalHeight\ExampleCoffin}|.
% \end{function}
%
% \begin{function}{\CoffinWidth}
%   \begin{syntax}
%     \cs{CoffinWidth} \meta{coffin}
%   \end{syntax}
%   Calculates the width of the \meta{coffin} in a form
%   suitable for use in a \meta{dimension expression}, for example
%   |\setlength{\mylength}{\CoffinWidth\ExampleCoffin}|.
% \end{function}
%
% \section{Diagnostic functions}
%
% Diagnostic data for following the coffin-building process is
% available both graphically and at the terminal. This reflects the
% fact that coffins are visual constructs.
%
% \begin{function}{\DisplayCoffinHandles}
%   \begin{syntax}
%     \cs{DisplayCoffinHandles} \meta{coffin} \Arg{color}
%   \end{syntax}
%   This function first calculates the intersections between all of
%   the \meta{poles} of the \meta{coffin} to give a set of
%   \meta{handles}. It then prints the \meta{coffin} at the current
%   location in the source, with the  position of the \meta{handles}
%   marked on the coffin. The \meta{handles} will be labeled as part
%   of this process: the locations of the \meta{handles} and the labels
%   are both printed in the \meta{color} specified.
% \end{function}
%
% \begin{function}{\MarkCoffinHandle}
%   \begin{syntax}
%     \cs{MarkCoffinHandle} \meta{coffin}
%     ~~[ \meta{pole1} , \meta{pole2} ] \Arg{color}
%   \end{syntax}
%   This function first calculates the \meta{handle} for the
%   \meta{coffin} as defined by the intersection of \meta{pole1} and
%   \meta{pole2}. It then marks the position of the \meta{handle}
%   on the \meta{coffin}. The \meta{handle} will be labeled as part of
%   this process: the location of the \meta{handle} and the label are
%   both printed in the \meta{color} specified. If no \meta{poles} are
%   give, the default |(H,l)| is used.
% \end{function}
%
% \begin{function}{\ShowCoffinStructure}
%   \begin{syntax}
%     \cs{ShowCoffinStructure} \meta{coffin}
%   \end{syntax}
%   This function shows the structural information about the
%   \meta{coffin} in the terminal. The width, height and depth of the
%   typeset material are given, along with the location of all of the
%   poles of the coffin. For example, for the rotated coffin in
%   Figure~\ref{fgr:rotation}, the output of \cs{ShowCoffinStructure}
%   is:
%   \begin{verbatim}
%     Size of coffin \ExampleCoffin:
%     > ht = 72.26999pt
%     > dp = 0.0pt
%     > wd = 72.26999pt
%     Poles of coffin \ExampleCoffin:
%     >  l  =>  {0pt}{0pt}{0pt}{1000pt}
%     >  B  =>  {0pt}{0pt}{1000pt}{0pt}
%     >  H  =>  {0pt}{0pt}{1000pt}{0pt}
%     >  T  =>  {0pt}{0pt}{1000pt}{0pt}
%     >  hc  =>  {36.135pt}{0pt}{0pt}{1000pt}
%     >  r  =>  {72.26999pt}{0pt}{0pt}{1000pt}
%     >  vc  =>  {0pt}{36.135pt}{1000pt}{0pt}
%     >  t  =>  {0pt}{72.26999pt}{1000pt}{0pt}
%     >  b  =>  {0pt}{0.0pt}{1000pt}{0pt}.
%     <recently read> }
%   \end{verbatim}
%   Notice that the poles of a coffin are defined by four values:
%   the $x$ and $y$ coordinates of a point that the pole
%   passes through and the $x$- and $y$-components of a
%   vector denoting the direction of the pole. It is the ratio between
%   the later, rather than the absolute values, which determines the
%   direction of the pole.
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{Implementation}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=coffin>
%    \end{macrocode}
%
%    \begin{macrocode}
\ProvidesExplPackage{xcoffins}{2026-05-15}{}
  {L3 Experimental design level coffins}
%    \end{macrocode}
%
% \begin{variable}
%   {
%     \l_@@_A_hpole_tl          ,
%     \l_@@_A_vpole_tl          ,
%     \l_@@_B_hpole_tl          ,
%     \l_@@_B_vpole_tl          ,
%     \l_@@_bound_box_grow_bool ,
%     \l_@@_hoffset_dim         ,
%     \l_@@_voffset_dim
%   }
%   Key--value definitions for the alignment system. With the exception
%   of \texttt{grow-bounding-box}, all of these have to be given with a
%   value.
%    \begin{macrocode}
\keys_define:nn { coffin }
  {
    coffin1-hpole     .tl_set:N         = \l_@@_A_hpole_tl          ,
    coffin1-hpole     .value_required:n = true                      ,
    coffin1-vpole     .tl_set:N         = \l_@@_A_vpole_tl          ,
    coffin1-vpole     .value_required:n = true                      ,
    coffin2-hpole     .tl_set:N         = \l_@@_B_hpole_tl          ,
    coffin2-hpole     .value_required:n = true                      ,
    coffin2-vpole     .tl_set:N         = \l_@@_B_vpole_tl          ,
    coffin2-vpole     .value_required:n = true                      ,
    grow-bounding-box .bool_set:N       = \l_@@_bound_box_grow_bool ,
    grow-bounding-box .default:n        = true                      ,
    hoffset           .dim_set:N        = \l_@@_hoffset_dim         ,
    hoffset           .value_required:n = true                      ,
    voffset           .dim_set:N        = \l_@@_voffset_dim         ,
    voffset           .value_required:n = true
  }
\keys_set:nn { coffin }
  {
    coffin1-hpole     = H    ,
    coffin1-vpole     = l    ,
    coffin2-hpole     = H    ,
    coffin2-vpole     = l    ,
    grow-bounding-box = true ,
    hoffset           = 0 pt ,
    voffset           = 0 pt
  }
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_design_names:N}
% \begin{variable}{\Height, \Depth, \Width, \TotalHeight}
% \begin{variable}
%   {\l_@@_height_dim, \l_@@_depth_dim, \l_@@_width_dim, \l_@@_totalheight_dim}
%   Sets up design-level names for the various coffin dimensions. These are
%   not defined outside of this scope, and are dimensions so that they work
%   correctly inside for example \cs{fp_eval:n}.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_design_names:N #1
  {
    \dim_set:Nn \l_@@_height_dim { \coffin_ht:N #1 }
    \dim_set:Nn \l_@@_depth_dim  { \coffin_dp:N #1 }
    \dim_set:Nn \l_@@_width_dim  { \coffin_wd:N #1 }
    \dim_set:Nn \l_@@_totalheight_dim
      { \l_@@_height_dim + \l_@@_depth_dim }
    \cs_set_eq:NN \Height \l_@@_height_dim
    \cs_set_eq:NN \Depth \l_@@_depth_dim
    \cs_set_eq:NN \Width \l_@@_width_dim
    \cs_set_eq:NN \TotalHeight \l_@@_totalheight_dim
  }
\dim_new:N \l_@@_height_dim
\dim_new:N \l_@@_depth_dim
\dim_new:N \l_@@_width_dim
\dim_new:N \l_@@_totalheight_dim
%    \end{macrocode}
% \end{variable}
% \end{variable}
% \end{macro}
%
% A lot of this is more-or-less just passing data straight through.
%
% \begin{macro}{\NewCoffin}
% This is a very easy conversion.
%    \begin{macrocode}
\NewDocumentCommand \NewCoffin { m }
  { \coffin_new:N #1 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\SetHorizontalCoffin}
% \begin{macro}{\SetVerticalCoffin}
%   These are again straight-forward translations.
%    \begin{macrocode}
\NewDocumentCommand \SetHorizontalCoffin { m +m }
  { \hcoffin_set:Nn #1 {#2} }
\NewDocumentCommand \SetVerticalCoffin { m m +m }
  { \vcoffin_set:Nnn #1 {#2} {#3} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\SetHorizontalPole}
% \begin{macro}{\SetVerticalPole}
%   Here, there is a need to set up the design-level names for coffin
%   dimensions. This requires grouping, but the coffin work has to occur
%   outside of the group. Hence there is a bit of expansion trickery.
%    \begin{macrocode}
\NewDocumentCommand \SetHorizontalPole { m m m }
  {
    \group_begin:
      \@@_design_names:N #1
    \use:e
      {
        \group_end:
        \coffin_set_horizontal_pole:Nnn #1
          { \exp_not:n {#2} } { \dim_eval:n {#3} }
      }
  }
\NewDocumentCommand \SetVerticalPole { m m m }
  {
    \group_begin:
      \@@_design_names:N #1
    \use:e
      {
        \group_end:
        \coffin_set_vertical_pole:Nnn #1
          { \exp_not:n {#2} } { \dim_eval:n {#3} }
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\JoinCoffins}
%   The \cs{JoinCoffins} function needs to do a bit of work on the input
%   syntax, as there are a number of optional arguments to worry about.
%   The idea here is that \cs{JoinCoffins} can be used to either expand
%   the bounding box of \meta{coffin1} or add \meta{coffin2} without any
%   expansion of the bounding box. There are also the two handle positions
%   and the offset to sort out.
%    \begin{macrocode}
\NewDocumentCommand \JoinCoffins
  {
    o
    s
    m
    > { \SplitArgument { 1 } { , } } O { H , l }
    m
    > { \SplitArgument { 1 } { , } } O { H , l }
    > { \SplitArgument { 1 } { , } } D ( ) { 0 pt , 0 pt }
  }
  {
    \IfNoValueTF {#1}
      {
        \IfBooleanTF #2
          { \coffin_attach:NnnNnnnn #3 #4 #5 #6 #7 }
          { \coffin_join:NnnNnnnn #3 #4 #5 #6 #7 }
      }
      {
        \group_begin:
          \keys_set:nn { coffin } {#1}
          \tl_set:Ne \l_@@_tmp_tl
            {
              \group_end:
              \bool_if:NTF \l_@@_bound_box_grow_bool
                { \coffin_join:NnnNnnnn }
                { \coffin_attach:NnnNnnnn }
              \exp_not:N #3
              { \exp_not:o { \l_@@_A_hpole_tl } }
              { \exp_not:o { \l_@@_A_vpole_tl } }
              \exp_not:N #5
              { \exp_not:o { \l_@@_B_hpole_tl } }
              { \exp_not:o { \l_@@_B_vpole_tl } }
              { \dim_use:N \l_@@_hoffset_dim }
              { \dim_use:N \l_@@_voffset_dim }
            }
        \l_@@_tmp_tl
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\TypesetCoffin}
%   For typesetting coffins there are two optional arguments, both of
%   which need to be split. This is a simpler case of the code needed for
%   \cs{JoinCoffins}.
%    \begin{macrocode}
\NewDocumentCommand \TypesetCoffin
  {
    m
    > { \SplitArgument { 1 } { , } } O { H , l }
    > { \SplitArgument { 1 } { , } } D ( ) { 0 pt , 0 pt }
  }
  { \coffin_typeset:Nnnnn #1 #2 #3 }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\RotateCoffin}
% \begin{macro}{\ResizeCoffin}
% \begin{macro}{\ScaleCoffin}
%   Mores straight-forward copies.
%    \begin{macrocode}
\NewDocumentCommand \RotateCoffin  { m m }
  { \coffin_rotate:Nn #1 {#2} }
\NewDocumentCommand \ResizeCoffin  { m m m }
  { \coffin_resize:Nnn #1 {#2} {#3} }
\NewDocumentCommand \ScaleCoffin  { m m m }
  { \coffin_scale:Nnn #1 {#2} {#3} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\CoffinDepth, \CoffinHeight, \CoffinTotalHeigth, \CoffinWidth}
%   Nothing too complex, except that the total height is set up as an
%   expression so that it will act correctly if prefixed with a negative
%   sign, etc.
%    \begin{macrocode}
\NewDocumentCommand \CoffinDepth { m }
  { \dim_eval:n { \coffin_dp:N #1 } }
\NewDocumentCommand \CoffinHeight { m }
  { \dim_eval:n { \coffin_ht:N #1 } }
\NewDocumentCommand \CoffinTotalHeight { m }
  { \dim_eval:n { \coffin_ht:N #1 + \coffin_dp:N #1 } }
\NewDocumentCommand \CoffinWidth { m }
  { \dim_eval:n { \coffin_wd:N #1 } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\DisplayCoffinHandles}
%   Displaying all of the handles is a bit easier, as there is no need
%   to worry about the handle.
%    \begin{macrocode}
\NewDocumentCommand \DisplayCoffinHandles { m m }
  { \coffin_if_exist:NT #1 { \coffin_display_handles:Nn #1 {#2} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\MarkCoffinHandle}
%   Marking a handle requires a bit of work with the input, so that
%   the design-level interface is \enquote{nice}.
%    \begin{macrocode}
\NewDocumentCommand \MarkCoffinHandle
  { m > { \SplitArgument { 1 } { , } } O { H , l } m }
  {  \coffin_if_exist:NT #1 { \coffin_mark_handle:Nnnn #1 #2 {#3} } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\ShowCoffinStructure}
%   Back again to easy-to-implement functions.
%    \begin{macrocode}
\NewDocumentCommand \ShowCoffinStructure { m }
  { \coffin_show_structure:N #1 }
%    \end{macrocode}
% \end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
