% \iffalse meta-comment
%
%% File: l3box.dtx
%
% Copyright (C) 2005-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 "l3kernel 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{l3box} module\\ Boxes^^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-26}
%
% \maketitle
%
% \begin{documentation}
%
% Box variables contain typeset material that can be inserted on the
% page or in other boxes.  Their contents cannot be converted back to
% lists of tokens.
% There are three kinds of box operations: horizontal mode denoted
% with prefix |\hbox_|, vertical mode with prefix |\vbox_|, and the
% generic operations working in both modes with prefix |\box_|.
% For instance, a new box variable containing the words \enquote{Hello,
% world!} (in a horizontal box) can be obtained by the following code.
% \begin{verbatim}
% \box_new:N \l_hello_box
% \hbox_set:Nn \l_hello_box { Hello, ~ world! }
% \end{verbatim}
% The argument is typeset inside a \TeX{} group so that any variables
% assigned during the construction of this box restores its value
% afterwards.
%
% Box variables from \pkg{l3box} are compatible with those of \LaTeXe{}
% and plain \TeX{} and can be used interchangeably.  The \pkg{l3box}
% commands to construct boxes, such as \cs{hbox:n} or \cs{hbox_set:Nn},
% are \enquote{color-safe}, meaning that
% \begin{verbatim}
% \hbox:n { \color_select:n { blue } Hello, } ~ world!
% \end{verbatim}
% will result in \enquote{Hello,} taking the color blue, but
% \enquote{world!} remaining with the prevailing color outside the box.
%
% \section{Creating and initializing boxes}
%
% \begin{function}{\box_new:N, \box_new:c}
%   \begin{syntax}
%     \cs{box_new:N} \meta{box}
%   \end{syntax}
%   Creates a new \meta{box} or raises an error if the name is
%   already taken. The declaration is global. The \meta{box} is
%   initially void.
% \end{function}
%
% \begin{function}{\box_clear:N, \box_clear:c, \box_gclear:N, \box_gclear:c}
%   \begin{syntax}
%     \cs{box_clear:N} \meta{box}
%   \end{syntax}
%   Clears the content of the \meta{box} by setting the box equal to
%   \cs{c_empty_box}.
% \end{function}
%
% \begin{function}
%   {\box_clear_new:N, \box_clear_new:c, \box_gclear_new:N, \box_gclear_new:c}
%   \begin{syntax}
%     \cs{box_clear_new:N} \meta{box}
%   \end{syntax}
%   Ensures that the \meta{box} exists globally by applying
%   \cs{box_new:N} if necessary, then applies
%   \cs[index=box_clear:N]{box_(g)clear:N} to leave
%   the \meta{box} empty.
% \end{function}
%
% \begin{function}
%   {
%     \box_set_eq:NN,  \box_set_eq:cN,  \box_set_eq:Nc,  \box_set_eq:cc,
%     \box_gset_eq:NN, \box_gset_eq:cN, \box_gset_eq:Nc, \box_gset_eq:cc
%   }
%   \begin{syntax}
%     \cs{box_set_eq:NN} \meta{box_1} \meta{box_2}
%   \end{syntax}
%   Sets the content of \meta{box_1} equal to that of \meta{box_2}.
% \end{function}
%
% \begin{function}[EXP, pTF, added=2012-03-03]
%   {\box_if_exist:N, \box_if_exist:c}
%   \begin{syntax}
%     \cs{box_if_exist_p:N} \meta{box}
%     \cs{box_if_exist:NTF} \meta{box} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests whether the \meta{box} is currently defined.  This does not
%   check that the \meta{box} really is a box.
% \end{function}
%
% \section{Using boxes}
%
% \begin{function}{\box_use:N, \box_use:c}
%   \begin{syntax}
%     \cs{box_use:N} \meta{box}
%   \end{syntax}
%   Inserts the current content of the \meta{box} onto the current
%   list for typesetting. An error is raised if the variable does
%   not exist or if it is invalid.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{copy}.
%   \end{texnote}
% \end{function}
%
% \begin{function}{\box_move_right:nn, \box_move_left:nn}
%   \begin{syntax}
%     \cs{box_move_right:nn} \Arg{dim expr} \Arg{box function}
%   \end{syntax}
%   This function operates in vertical mode, and inserts the
%   material specified by the \meta{box function}
%   such that its reference point is displaced horizontally by the given
%   \meta{dim expr} from the reference point for typesetting, to the right
%   or left as appropriate. The \meta{box function} should be
%   a box operation such as \cs{box_use:N} |\<box>| or a \enquote{raw}
%   box specification such as \cs{vbox:n} |{ xyz }|.
% \end{function}
%
% \begin{function}{\box_move_up:nn, \box_move_down:nn}
%   \begin{syntax}
%     \cs{box_move_up:nn} \Arg{dim expr} \Arg{box function}
%   \end{syntax}
%   This function operates in horizontal mode, and inserts the
%   material specified by the \meta{box function}
%   such that its reference point is displaced vertically by the given
%   \meta{dim expr} from the reference point for typesetting, up
%   or down as appropriate. The \meta{box function} should be
%   a box operation such as \cs{box_use:N} |\<box>| or a \enquote{raw}
%   box specification such as \cs{vbox:n} |{ xyz }|.
% \end{function}
%
% \section{Measuring and setting box dimensions}
%
% \begin{function}{\box_dp:N, \box_dp:c}
%   \begin{syntax}
%     \cs{box_dp:N} \meta{box}
%   \end{syntax}
%   Calculates the depth (below the baseline) of the \meta{box}
%   in a form suitable for use in a \meta{dim expr}.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{dp}.
%   \end{texnote}
% \end{function}
%
% \begin{function}{\box_ht:N, \box_ht:c}
%   \begin{syntax}
%     \cs{box_ht:N} \meta{box}
%   \end{syntax}
%   Calculates the height (above the baseline) of the \meta{box}
%   in a form suitable for use in a \meta{dim expr}.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{ht}.
%   \end{texnote}
% \end{function}
%
% \begin{function}{\box_wd:N, \box_wd:c}
%   \begin{syntax}
%     \cs{box_wd:N} \meta{box}
%   \end{syntax}
%   Calculates the width of the \meta{box} in a form
%   suitable for use in a \meta{dim expr}.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{wd}.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2021-05-05]{\box_ht_plus_dp:N, \box_ht_plus_dp:c}
%   \begin{syntax}
%     \cs{box_ht_plus_dp:N} \meta{box}
%   \end{syntax}
%   Calculates the total vertical size (height plus depth) of the \meta{box}
%   in a form suitable for use in a \meta{dim expr}.
% \end{function}
%
% \begin{function}[updated = 2019-01-22]
%   {
%     \box_set_dp:Nn, \box_set_dp:cn,
%     \box_gset_dp:Nn, \box_gset_dp:cn
%   }
%   \begin{syntax}
%     \cs{box_set_dp:Nn} \meta{box} \Arg{dim expr}
%   \end{syntax}
%   Set the depth (below the baseline) of the \meta{box} to the value of
%   the \Arg{dim expr}.
% \end{function}
%
% \begin{function}[updated = 2019-01-22]
%   {
%     \box_set_ht:Nn, \box_set_ht:cn,
%     \box_gset_ht:Nn, \box_gset_ht:cn
%   }
%   \begin{syntax}
%     \cs{box_set_ht:Nn} \meta{box} \Arg{dim expr}
%   \end{syntax}
%   Set the height (above the baseline) of the \meta{box} to the value of
%   the \Arg{dim expr}.
% \end{function}
%
% \begin{function}[updated = 2019-01-22]
%   {
%     \box_set_wd:Nn, \box_set_wd:cn,
%     \box_gset_wd:Nn, \box_gset_wd:cn
%   }
%   \begin{syntax}
%     \cs{box_set_wd:Nn} \meta{box} \Arg{dim expr}
%   \end{syntax}
%   Set the width of the \meta{box} to the value of the
%   \Arg{dim expr}.
% \end{function}
%
% \section{Box conditionals}
%
% \begin{function}[EXP,pTF]{\box_if_empty:N, \box_if_empty:c}
%   \begin{syntax}
%     \cs{box_if_empty_p:N} \meta{box}
%     \cs{box_if_empty:NTF} \meta{box} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if \meta{box} is a empty (equal to \cs{c_empty_box}).
% \end{function}
%
% \begin{function}[EXP,pTF]{\box_if_horizontal:N, \box_if_horizontal:c}
%   \begin{syntax}
%     \cs{box_if_horizontal_p:N} \meta{box}
%     \cs{box_if_horizontal:NTF} \meta{box} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if \meta{box} is a horizontal box.
% \end{function}
%
% \begin{function}[EXP,pTF]{\box_if_vertical:N, \box_if_vertical:c}
%   \begin{syntax}
%     \cs{box_if_vertical_p:N} \meta{box}
%     \cs{box_if_vertical:NTF} \meta{box} \Arg{true code} \Arg{false code}
%   \end{syntax}
%   Tests if \meta{box} is a vertical box.
% \end{function}
%
% \section{The last box inserted}
%
% \begin{function}
%   {
%     \box_set_to_last:N,  \box_set_to_last:c,
%     \box_gset_to_last:N, \box_gset_to_last:c
%   }
%   \begin{syntax}
%     \cs{box_set_to_last:N} \meta{box}
%   \end{syntax}
%   Sets the \meta{box} equal to the last item (box) added to the current
%   partial list, removing the item from the list at the same time. When
%   applied to the main vertical list, the \meta{box} is always void as
%   it is not possible to recover the last added item.
% \end{function}
%
% \section{Constant boxes}
%
% \begin{variable}[updated = 2012-11-04]{\c_empty_box}
%   This is a permanently empty box, which is neither set as horizontal
%   nor vertical.
%   \begin{texnote}
%     At the \TeX{} level this is a void box.
%   \end{texnote}
% \end{variable}
%
% \section{Scratch boxes}
%
% \begin{variable}[updated = 2012-11-04]{\l_tmpa_box, \l_tmpb_box}
%   Scratch boxes for local assignment. These are never used by
%   the kernel code, and so are safe for use with any \LaTeX3-defined
%   function. However, they may be overwritten by other non-kernel
%   code and so should only be used for short-term storage.
% \end{variable}
%
% \begin{variable}{\g_tmpa_box, \g_tmpb_box}
%   Scratch boxes for global assignment. These are never used by
%   the kernel code, and so are safe for use with any \LaTeX3-defined
%   function. However, they may be overwritten by other non-kernel
%   code and so should only be used for short-term storage.
% \end{variable}
%
% \section{Viewing box contents}
%
% \begin{function}[updated = 2012-05-11]{\box_show:N, \box_show:c}
%   \begin{syntax}
%      \cs{box_show:N} \meta{box}
%   \end{syntax}
%   Shows full details of the content of the \meta{box} in the terminal.
% \end{function}
%
% \begin{function}[added = 2012-05-11]{\box_show:Nnn, \box_show:cnn}
%   \begin{syntax}
%      \cs{box_show:Nnn} \meta{box} \Arg{int expr_1} \Arg{int expr_2}
%   \end{syntax}
%   Display the contents of \meta{box} in the terminal, showing the first
%   \meta{int expr_1} items of the box, and descending into \meta{int expr_2}
%   group levels.
% \end{function}
%
% \begin{function}[added = 2012-05-11]{\box_log:N, \box_log:c}
%   \begin{syntax}
%      \cs{box_log:N} \meta{box}
%   \end{syntax}
%   Writes full details of the content of the \meta{box} to the log.
% \end{function}
%
% \begin{function}[added = 2012-05-11]{\box_log:Nnn, \box_log:cnn}
%   \begin{syntax}
%      \cs{box_log:Nnn} \meta{box} \Arg{int expr_1} \Arg{int expr_2}
%   \end{syntax}
%   Writes the contents of \meta{box} to the log, showing the first
%   \meta{int expr_1} items of the box, and descending into \meta{int expr_2}
%   group levels.
% \end{function}
%
% \section{Boxes and color}
%
% All \LaTeX{}3 boxes are \enquote{color safe}: a color set inside the box
% stops applying after the end of the box has occurred.
%
% \section{Horizontal mode boxes}
%
% \begin{function}[updated = 2017-04-05]{\hbox:n}
%   \begin{syntax}
%     \cs{hbox:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a horizontal box of natural
%   width and then includes this box in the current list for typesetting.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]{\hbox_to_wd:nn}
%   \begin{syntax}
%     \cs{hbox_to_wd:nn} \Arg{dim expr} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a horizontal box of width
%   \meta{dim expr} and then includes this box in the current list for
%   typesetting.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]{\hbox_to_zero:n}
%   \begin{syntax}
%     \cs{hbox_to_zero:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a horizontal box of zero width
%   and then includes this box in the current list for typesetting.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]
%   {\hbox_set:Nn, \hbox_set:cn, \hbox_gset:Nn, \hbox_gset:cn}
%   \begin{syntax}
%     \cs{hbox_set:Nn} \meta{box} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} at natural width and then stores the
%   result inside the \meta{box}.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]
%   {
%     \hbox_set_to_wd:Nnn,  \hbox_set_to_wd:cnn,
%     \hbox_gset_to_wd:Nnn, \hbox_gset_to_wd:cnn
%   }
%   \begin{syntax}
%     \cs{hbox_set_to_wd:Nnn} \meta{box} \Arg{dim expr} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} to the width given by the \meta{dim expr}
%   and then stores the result inside the \meta{box}.
% \end{function}
%
% \begin{function}[added = 2020-08-25]{\hbox_overlap_center:n}
%   \begin{syntax}
%     \cs{hbox_overlap_center:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a horizontal box of zero width
%   such that material protrudes equally to both sides of the insertion point.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]{\hbox_overlap_right:n}
%   \begin{syntax}
%     \cs{hbox_overlap_right:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a horizontal box of zero width
%   such that material protrudes to the right of the insertion point.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]{\hbox_overlap_left:n}
%   \begin{syntax}
%     \cs{hbox_overlap_left:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a horizontal box of zero width
%   such that material protrudes to the left of the insertion point.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]
%   {
%     \hbox_set:Nw, \hbox_set:cw,
%     \hbox_set_end:,
%     \hbox_gset:Nw, \hbox_gset:cw,
%     \hbox_gset_end:
%   }
%   \begin{syntax}
%     \cs{hbox_set:Nw} \meta{box} \meta{contents} \cs{hbox_set_end:}
%   \end{syntax}
%   Typesets the \meta{contents} at natural width and then stores the
%   result inside the \meta{box}. In contrast
%   to \cs{hbox_set:Nn} this function does not absorb the argument
%   when finding the \meta{content}, and so can be used in circumstances
%   where the \meta{content} may not be a simple argument.
% \end{function}
%
% \begin{function}[added = 2017-06-08]
%   {
%     \hbox_set_to_wd:Nnw,  \hbox_set_to_wd:cnw,
%     \hbox_gset_to_wd:Nnw, \hbox_gset_to_wd:cnw
%   }
%   \begin{syntax}
%     \cs{hbox_set_to_wd:Nnw} \meta{box} \Arg{dim expr} \meta{contents} \cs{hbox_set_end:}
%   \end{syntax}
%   Typesets the \meta{contents} to the width given by the \meta{dim expr}
%   and then stores the result inside the \meta{box}. In contrast
%   to \cs{hbox_set_to_wd:Nnn} this function does not absorb the argument
%   when finding the \meta{content}, and so can be used in circumstances
%   where the \meta{content} may not be a simple argument.
% \end{function}
%
% \begin{function}{\hbox_unpack:N, \hbox_unpack:c}
%   \begin{syntax}
%     \cs{hbox_unpack:N} \meta{box}
%   \end{syntax}
%   Unpacks the content of the horizontal \meta{box}, retaining any stretching
%   or shrinking applied when the \meta{box} was set.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{unhcopy}.
%   \end{texnote}
% \end{function}
%
% \section{Vertical mode boxes}
%
% Vertical boxes inherit their baseline from their contents. The
% standard case is that the baseline of the box is at the same position
% as that of the last item added to the box. This means that the box
% has no depth unless the last item added to it had depth. As a
% result most vertical boxes have a large height value and small or
% zero depth. The exception are |_top| boxes, where the reference point
% is that of the first item added. These tend to have a large depth and
% small height, although the latter is typically non-zero.
%
% \begin{function}[updated = 2017-04-05]{\vbox:n}
%   \begin{syntax}
%     \cs{vbox:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of natural height
%   and includes this box in the current list for typesetting.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]{\vbox_top:n}
%   \begin{syntax}
%     \cs{vbox_top:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of natural height
%   and includes this box in the current list for typesetting. The
%   vertical position of reference point of the box is equal to the
%   baseline of the \emph{first} item added to the box.
% \end{function}
%
% \begin{function}[added = 2026-02-17]{\vbox_center:n}
%   \begin{syntax}
%     \cs{vbox_center:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of natural height
%   and includes this box in the current list for typesetting. The
%   vertical position of  reference point of the box is at the vertical
%   midpoint of content of the box.
% \end{function}
%
% \begin{function}[added = 2026-02-25]{\vbox:w, \vbox_top:w, \vbox_center:w, \vbox_end:}
%   \begin{syntax}
%     \cs{vbox:w}
%     \meta{contents}
%     \cs{vbox_end:}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of natural height
%   and includes this box in the current list for typesetting. The reference
%   of the box is determined as for the matching |:n| function.
% \end{function}
%
% \begin{function}[added = 2026-02-17, updated = 2026-02-24]
%   {\vbox:nn, \vbox_top:nn, \vbox_center:nn}
%   \begin{syntax}
%     \cs{vbox_center:nn} \Arg{offset} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of natural height
%   and includes this box in the current list for typesetting. The reference
%   of the box is determined as for the matching |:n| function. The box
%   is then displaced vertically by the \meta{offset} (a \meta{dim expr})
%   from existing baseline.
%   \begin{texnote}
%     If the \meta{offset} makes use of math font dimensions, these
%     should be correctly initialized. In \LaTeX{}, this would be achieved
%     by applying \tn{check@mathfonts} immediately before using the
%     functions. If the \meta{offset} is the math axis
%     (|\fontdimen22\textfont2|), the dimensions of the resulting box will
%     be identical to those from \tn{vcenter}.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2026-02-25]{\vbox:nw, \vbox_top:nw, \vbox_center:nw}
%   \begin{syntax}
%     \cs{vbox:nw} \Arg{offset}
%     \meta{contents}
%     \cs{vbox_end:}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of natural height
%   and includes this box in the current list for typesetting. The reference
%   of the box is determined as for the matching |:n| function. The box
%   is then displaced vertically by the \meta{offset}  (a \meta{dim expr})
%   from existing baseline.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]{\vbox_to_ht:nn}
%   \begin{syntax}
%     \cs{vbox_to_ht:nn} \Arg{dim expr} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of height
%   \meta{dim expr} and then includes this box in the current list for
%   typesetting.
% \end{function}
%
% \begin{function}[added = 2026-02-01]{\vbox_top_to_ht:nn}
%   \begin{syntax}
%     \cs{vbox_top_to_ht:nn} \Arg{dim expr} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of height
%   \meta{dim expr} and then includes this box in the current list for
%   typesetting. The vertical position of reference point of the box
%   is equal to the baseline of the \emph{first} item added to the box.
% \end{function}
%
% \begin{function}[added = 2026-02-17]{\vbox_center_to_ht:nn}
%   \begin{syntax}
%     \cs{vbox_center_to_ht:nn} \Arg{dim expr} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of height
%   \meta{dim expr} and then includes this box in the current list for
%   typesetting. The vertical position of  reference point of the box
%   is at the vertical midpoint of content of the box.
% \end{function}
%
% \begin{function}[added = 2026-02-25]
%   {\vbox_to_ht:nw, \vbox_top_to_ht:nw, \vbox_center_to_ht:nw}
%   \begin{syntax}
%     \cs{vbox_to_ht:nw} \Arg{dim expr}
%     \meta{contents}
%     \cs{vbox_end:}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of height \meta{dim expr}
%   and includes this box in the current list for typesetting. The reference
%   of the box is determined as for the matching |:nn| function.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]{\vbox_to_zero:n}
%   \begin{syntax}
%     \cs{vbox_to_zero:n} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} into a vertical box of zero height
%   and then includes this box in the current list for typesetting.
% \end{function}
%
%  \begin{function}[updated = 2017-04-05]
%    {\vbox_set:Nn, \vbox_set:cn, \vbox_gset:Nn, \vbox_gset:cn}
%   \begin{syntax}
%     \cs{vbox_set:Nn} \meta{box} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} at natural height and then stores the
%   result inside the \meta{box}.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]
%   {\vbox_set_top:Nn, \vbox_set_top:cn, \vbox_gset_top:Nn, \vbox_gset_top:cn}
%   \begin{syntax}
%     \cs{vbox_set_top:Nn} \meta{box} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} at natural height and then stores the
%   result inside the \meta{box}. The baseline of the box is equal
%   to that of the \emph{first} item added to the box.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]
%   {
%     \vbox_set_to_ht:Nnn,  \vbox_set_to_ht:cnn,
%     \vbox_gset_to_ht:Nnn, \vbox_gset_to_ht:cnn
%   }
%   \begin{syntax}
%     \cs{vbox_set_to_ht:Nnn} \meta{box} \Arg{dim expr} \Arg{contents}
%   \end{syntax}
%   Typesets the \meta{contents} to the height given by the
%   \meta{dim expr} and then stores the result inside the \meta{box}.
% \end{function}
%
% \begin{function}[updated = 2017-04-05]
%   {
%     \vbox_set:Nw, \vbox_set:cw,
%     \vbox_set_end:,
%     \vbox_gset:Nw, \vbox_gset:cw,
%     \vbox_gset_end:
%   }
%   \begin{syntax}
%     \cs{vbox_set:Nw} \meta{box} \meta{contents} \cs{vbox_set_end:}
%   \end{syntax}
%   Typesets the \meta{contents} at natural height and then stores the
%   result inside the \meta{box}. In contrast
%   to \cs{vbox_set:Nn} this function does not absorb the argument
%   when finding the \meta{content}, and so can be used in circumstances
%   where the \meta{content} may not be a simple argument.
% \end{function}
%
% \begin{function}[added = 2017-06-08]
%   {
%     \vbox_set_to_ht:Nnw,  \vbox_set_to_ht:cnw,
%     \vbox_gset_to_ht:Nnw, \vbox_gset_to_ht:cnw
%   }
%   \begin{syntax}
%     \cs{vbox_set_to_ht:Nnw} \meta{box} \Arg{dim expr} \meta{contents} \cs{vbox_set_end:}
%   \end{syntax}
%   Typesets the \meta{contents} to the height given by the \meta{dim expr}
%   and then stores the result inside the \meta{box}. In contrast
%   to \cs{vbox_set_to_ht:Nnn} this function does not absorb the argument
%   when finding the \meta{content}, and so can be used in circumstances
%   where the \meta{content} may not be a simple argument.
% \end{function}
%
%
% \begin{function}[updated = 2018-12-29]
%   {
%     \vbox_set_split_to_ht:NNn, \vbox_set_split_to_ht:cNn,
%     \vbox_set_split_to_ht:Ncn, \vbox_set_split_to_ht:ccn,
%     \vbox_gset_split_to_ht:NNn, \vbox_gset_split_to_ht:cNn,
%     \vbox_gset_split_to_ht:Ncn, \vbox_gset_split_to_ht:ccn
%   }
%   \begin{syntax}
%      \cs{vbox_set_split_to_ht:NNn} \meta{box_1} \meta{box_2} \Arg{dim expr}
%   \end{syntax}
%   Sets \meta{box_1} to contain material to the height given by the
%   \meta{dim expr} by removing content from the top of \meta{box_2}
%   (which must be a vertical box).
% \end{function}
%
% \begin{function}{\vbox_unpack:N, \vbox_unpack:c}
%   \begin{syntax}
%     \cs{vbox_unpack:N} \meta{box}
%   \end{syntax}
%   Unpacks the content of the vertical \meta{box}, retaining any stretching
%   or shrinking applied when the \meta{box} was set.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{unvcopy}.
%   \end{texnote}
% \end{function}
%
% \section{Using boxes efficiently}
%
% The functions above for using box contents work in exactly the same
% way as for any other \pkg{expl3} variable. However, for efficiency
% reasons, it is also useful to have functions which \emph{drop} box
% contents on use. When a box is dropped, the box becomes empty at the group
% level \emph{where the box was originally set} rather than necessarily
% \emph{at the current group level}. For example, with
% \begin{verbatim}
%   \hbox_set:Nn \l_tmpa_box { A }
%   \group_begin:
%     \hbox_set:Nn \l_tmpa_box { B }
%      \group_begin:
%      \box_use_drop:N \l_tmpa_box
%     \group_end:
%     \box_show:N \l_tmpa_box
%   \group_end:
%   \box_show:N \l_tmpa_box
%   \end{verbatim}
% the first use of \cs{box_show:N} will show an entirely cleared (void) box, and the
% second will show the letter |A| in the box.
%
% These functions should be preferred when the content of the box is no
% longer required after use. Note that due to the unusual scoping behavior of
% \texttt{drop} functions they may be applied to both local and global boxes:
% the latter will naturally be set and thus cleared at a global level.
%
% \begin{function}{\box_use_drop:N, \box_use_drop:c}
%   \begin{syntax}
%     \cs{box_use_drop:N} \meta{box}
%   \end{syntax}
%   Inserts the current content of the \meta{box} onto the current
%   list for typesetting then drops the box content.  An error is raised if the
%   variable does not exist or if it is invalid. This function may be applied to
%   local or global boxes.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{box}.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2019-01-17]
%   {
%     \box_set_eq_drop:NN, \box_set_eq_drop:cN,
%     \box_set_eq_drop:Nc, \box_set_eq_drop:cc
%   }
%   \begin{syntax}
%     \cs{box_set_eq_drop:NN} \meta{box_1} \meta{box_2}
%   \end{syntax}
%   Sets the content of \meta{box_1} equal to that of \meta{box_2}, then
%   drops \meta{box_2}.
% \end{function}
%
% \begin{function}[added = 2019-01-17]
%   {
%     \box_gset_eq_drop:NN, \box_gset_eq_drop:cN,
%     \box_gset_eq_drop:Nc, \box_gset_eq_drop:cc
%   }
%   \begin{syntax}
%     \cs{box_gset_eq_drop:NN} \meta{box_1} \meta{box_2}
%   \end{syntax}
%   Sets the content of \meta{box_1} globally equal to that of \meta{box_2},
%   then drops \meta{box_2}.
% \end{function}
%
% \begin{function}[added = 2019-01-17]
%   {\hbox_unpack_drop:N, \hbox_unpack_drop:c}
%   \begin{syntax}
%     \cs{hbox_unpack_drop:N} \meta{box}
%   \end{syntax}
%   Unpacks the content of the horizontal \meta{box}, retaining any stretching
%   or shrinking applied when the \meta{box} was set. The original \meta{box}
%   is then dropped.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{unhbox}.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2019-01-17]
%   {\vbox_unpack_drop:N, \vbox_unpack_drop:c}
%   \begin{syntax}
%     \cs{vbox_unpack_drop:N} \meta{box}
%   \end{syntax}
%   Unpacks the content of the vertical \meta{box}, retaining any stretching
%   or shrinking applied when the \meta{box} was set. The original \meta{box}
%   is then dropped.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{unvbox}.
%   \end{texnote}
% \end{function}
%
% \section{Affine transformations}
%
% Affine transformations are changes which (informally) preserve straight
% lines. Simple translations are affine transformations, but are better handled
% in \TeX{} by doing the translation first, then inserting an unmodified box.
% On the other hand, rotation and resizing of boxed material can best be
% handled by modifying boxes. These transformations are described here.
%
% \begin{function}[added = 2017-04-04, updated = 2019-01-22]
%   {
%     \box_autosize_to_wd_and_ht:Nnn, \box_autosize_to_wd_and_ht:cnn,
%     \box_gautosize_to_wd_and_ht:Nnn, \box_gautosize_to_wd_and_ht:cnn,
%   }
%   \begin{syntax}
%     \cs{box_autosize_to_wd_and_ht:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
%   \end{syntax}
%   Resizes the \meta{box} to fit within the given \meta{x-size} (horizontally)
%   and \meta{y-size} (vertically); both of the sizes are dimension
%   expressions. The \meta{y-size} is the height only: it does not include any
%   depth. The updated \meta{box} is an |hbox|, irrespective of the nature
%   of the \meta{box} before the resizing is applied. The final size of the
%   \meta{box} is the smaller of \Arg{x-size} and \Arg{y-size},
%   i.e., the result fits within the dimensions specified. Negative
%   sizes cause the material in the \meta{box} to be reversed in direction,
%   but the reference point of the \meta{box} is unchanged. Thus a negative
%   \meta{y-size} results in the \meta{box} having a depth dependent on the
%   height of the original and \emph{vice versa}.
% \end{function}
%
% \begin{function}[added = 2017-04-04, updated = 2019-01-22]
%   {
%     \box_autosize_to_wd_and_ht_plus_dp:Nnn,
%     \box_autosize_to_wd_and_ht_plus_dp:cnn,
%     \box_gautosize_to_wd_and_ht_plus_dp:Nnn,
%     \box_gautosize_to_wd_and_ht_plus_dp:cnn
%   }
%   \begin{syntax}
%     \cs{box_autosize_to_wd_and_ht_plus_dp:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
%   \end{syntax}
%   Resizes the \meta{box} to fit within the given \meta{x-size} (horizontally)
%   and \meta{y-size} (vertically); both of the sizes are dimension
%   expressions. The \meta{y-size} is the total vertical size (height plus
%   depth). The updated \meta{box} is an |hbox|, irrespective of the nature
%   of the \meta{box} before the resizing is applied. The final size of the
%   \meta{box} is the smaller of \Arg{x-size} and \Arg{y-size},
%   i.e., the result fits within the dimensions specified. Negative
%   sizes cause the material in the \meta{box} to be reversed in direction,
%   but the reference point of the \meta{box} is unchanged. Thus a negative
%   \meta{y-size} results in the \meta{box} having a depth dependent on the
%   height of the original and \emph{vice versa}.
% \end{function}
%
% \begin{function}[updated = 2019-01-22]
%   {
%     \box_resize_to_ht:Nn, \box_resize_to_ht:cn,
%     \box_gresize_to_ht:Nn, \box_gresize_to_ht:cn
%   }
%   \begin{syntax}
%     \cs{box_resize_to_ht:Nn} \meta{box} \Arg{y-size}
%   \end{syntax}
%   Resizes the \meta{box} to \meta{y-size} (vertically), scaling the horizontal
%   size by the same amount; \meta{y-size} is a dimension expression. The
%   \meta{y-size} is the height only: it does not include any depth. The updated
%   \meta{box} is an |hbox|, irrespective of the nature of the \meta{box}
%   before the resizing is applied. A negative \meta{y-size} causes the
%   material in the \meta{box} to be reversed in direction, but the reference
%   point of the \meta{box} is unchanged. Thus a negative \meta{y-size}
%   results in the \meta{box} having a depth dependent on the height of the
%   original and \emph{vice versa}.
% \end{function}
%
% \begin{function}[updated = 2019-01-22]
%   {
%     \box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn,
%     \box_gresize_to_ht_plus_dp:Nn, \box_gresize_to_ht_plus_dp:cn,
%   }
%   \begin{syntax}
%     \cs{box_resize_to_ht_plus_dp:Nn} \meta{box} \Arg{y-size}
%   \end{syntax}
%   Resizes the \meta{box} to \meta{y-size} (vertically), scaling the horizontal
%   size by the same amount; \meta{y-size} is a dimension expression. The
%   \meta{y-size} is the total vertical size (height plus depth). The updated
%   \meta{box} is an |hbox|, irrespective of the nature of the \meta{box}
%   before the resizing is applied. A negative \meta{y-size} causes
%   the material in the \meta{box} to be reversed in direction, but the
%   reference point of the \meta{box} is unchanged. Thus a negative
%   \meta{y-size} results in the \meta{box} having a depth dependent on the
%   height of the original and \emph{vice versa}.
% \end{function}
%
% \begin{function}[updated = 2019-01-22]
%   {
%     \box_resize_to_wd:Nn, \box_resize_to_wd:cn,
%     \box_gresize_to_wd:Nn, \box_gresize_to_wd:cn
%   }
%   \begin{syntax}
%     \cs{box_resize_to_wd:Nn} \meta{box} \Arg{x-size}
%   \end{syntax}
%   Resizes the \meta{box} to \meta{x-size} (horizontally), scaling the vertical
%   size by the same amount; \meta{x-size} is a dimension expression. The updated
%   \meta{box} is an |hbox|, irrespective of the nature of the \meta{box}
%   before the resizing is applied. A negative \meta{x-size} causes the
%   material in the \meta{box} to be reversed in direction, but the reference
%   point of the \meta{box} is unchanged. Thus a negative \meta{x-size}
%   results in the \meta{box} having a depth dependent on the height of the
%   original and \emph{vice versa}.
% \end{function}
%
% \begin{function}[added = 2014-07-03, updated = 2019-01-22]
%   {
%     \box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn,
%     \box_gresize_to_wd_and_ht:Nnn, \box_gresize_to_wd_and_ht:cnn
%   }
%   \begin{syntax}
%     \cs{box_resize_to_wd_and_ht:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
%   \end{syntax}
%   Resizes the \meta{box} to \meta{x-size} (horizontally) and \meta{y-size}
%   (vertically): both of the sizes are dimension expressions. The
%   \meta{y-size} is the height only and does not include any depth. The updated
%   \meta{box} is an |hbox|, irrespective of the nature of the \meta{box}
%   before the resizing is applied. Negative sizes cause the material in
%   the \meta{box} to be reversed in direction, but the reference point of the
%   \meta{box} is unchanged. Thus a negative \meta{y-size} results in
%   the \meta{box} having a depth dependent on the height of the original and
%   \emph{vice versa}.
% \end{function}
%
% \begin{function}[added = 2017-04-06, updated = 2019-01-22]
%   {
%     \box_resize_to_wd_and_ht_plus_dp:Nnn,
%     \box_resize_to_wd_and_ht_plus_dp:cnn,
%     \box_gresize_to_wd_and_ht_plus_dp:Nnn,
%     \box_gresize_to_wd_and_ht_plus_dp:cnn
%   }
%   \begin{syntax}
%     \cs{box_resize_to_wd_and_ht_plus_dp:Nnn} \meta{box} \Arg{x-size} \Arg{y-size}
%   \end{syntax}
%   Resizes the \meta{box} to \meta{x-size} (horizontally) and \meta{y-size}
%   (vertically): both of the sizes are dimension expressions. The
%   \meta{y-size} is the total vertical size (height plus depth). The updated
%   \meta{box} is an |hbox|, irrespective of the nature of the \meta{box}
%   before the resizing is applied. Negative sizes cause the material in
%   the \meta{box} to be reversed in direction, but the reference point of the
%   \meta{box} is unchanged. Thus a negative \meta{y-size} results in
%   the \meta{box} having a depth dependent on the height of the original and
%   \emph{vice versa}.
% \end{function}
%
% \begin{function}[updated = 2019-01-22]
%   {
%     \box_rotate:Nn, \box_rotate:cn,
%     \box_grotate:Nn, \box_grotate:cn
%   }
%   \begin{syntax}
%     \cs{box_rotate:Nn} \meta{box} \Arg{angle}
%   \end{syntax}
%   Rotates the \meta{box} by \meta{angle} (a \meta{fp expr} in degrees)
%   anti-clockwise about
%   its reference point. The reference point of the updated box is moved
%   horizontally such that it is at the left side of the smallest rectangle
%   enclosing the rotated material. The updated \meta{box} is an |hbox|,
%   irrespective of the nature of the \meta{box} before the rotation is applied.
% \end{function}
%
% \begin{function}[updated = 2019-01-22]
%   {
%     \box_scale:Nnn, \box_scale:cnn,
%     \box_gscale:Nnn, \box_gscale:cnn
%   }
%   \begin{syntax}
%     \cs{box_scale:Nnn} \meta{box} \Arg{x-scale} \Arg{y-scale}
%   \end{syntax}
%   Scales the \meta{box} by factors \meta{x-scale} and \meta{y-scale} in
%   the horizontal and vertical directions, respectively (both scales are
%   \meta{fp expr}). The updated \meta{box} is an |hbox|, irrespective
%   of the nature of the \meta{box} before the scaling is applied. Negative
%   scalings cause the material in the \meta{box} to be reversed in
%   direction, but the reference point of the \meta{box} is unchanged.
%   Thus a negative \meta{y-scale} results in the \meta{box} having a depth
%   dependent on the height of the original and \emph{vice versa}.
% \end{function}
%
% \section{Framing boxes}
%
% \begin{function}[added = 2026-03-16]
%   {
%     \box_frame:Nnn, \box_frame:cnn,
%     \box_gframe:Nnn, \box_gframe:cnn
%   }
%   \begin{syntax}
%     \cs{box_frame:Nnn} \meta{box} \Arg{separation} \Arg{thickness} \\
%   \end{syntax}
%   Adds a frame of \meta{thickness} (a \meta{dimexpr}) to the \meta{box}.
%   The \meta{separation} (a \meta{dimexpr}) is left between the existing content
%   and the frame. The updated \meta{box} is an |hbox|, irrespective
%   of the nature of the \meta{box} before the frame is applied.
%   The frame will overprint any part of the content which
%   lies outside of the bounding box at natural size (i.e., the frame is
%   printed \enquote{after} the content). The apparent size of the
%   inserted box includes the frame and the border, i.e., the width
%   of the inserted material is $\mathrm{width}(\meta{content}) +
%   2(\meta{thickness} + \meta{separation})$.
%   The vertical position of the reference point of the box is unchanged
%   by this function; the horizontal reference point is at the left of
%   the box, i.e., the original content is displaced rightward by the
%   \Arg{separation} and the \Arg{thickness}.
% \end{function}
%
% \begin{function}[added = 2026-03-16]
%   {
%     \box_underline:Nnn, \box_underline:cnn,
%     \box_gunderline:Nnn, \box_gunderline:cnn
%   }
%   \begin{syntax}
%     \cs{box_underline:Nnn} \meta{box} \Arg{separation} \Arg{thickness} \\
%   \end{syntax}
%   Adds an underline of \meta{thickness} (a \meta{dimexpr}) to the \meta{box}.
%   The \meta{separation} (a \meta{dimexpr}) is left between the existing content
%   and the line. The updated \meta{box} is an |hbox|, irrespective
%   of the nature of the \meta{box} before the line is applied.
%   The underline will overprint any part of the content which
%   lies outside of the bounding box at natural size (i.e., the line is
%   printed \enquote{after} the content). The apparent size of the inserted
%   box includes the underline and the border, this affects only the depth.
%   The vertical and horizontal positions of the reference point of the box
%   are unchanged by this function.
% \end{function}
%
% \section{Viewing part of a box}
%
% \begin{function}[updated = 2023-04-14]
%   {
%     \box_set_clipped:N, \box_set_clipped:c,
%     \box_gset_clipped:N, \box_gset_clipped:c
%   }
%   \begin{syntax}
%     \cs{box_set_clipped:N} \meta{box}
%   \end{syntax}
%   Clips the \meta{box} in the output so that only material inside the
%   bounding box is displayed in the output. The updated \meta{box} is an
%   hbox, irrespective of the nature of the \meta{box} before the clipping is
%   applied. Additional box levels are also generated by this operation.
%
%   \begin{texnote}
%     Clipping is implemented by the driver, and as such the full content of
%     the box is placed in the output file. Thus clipping does not remove
%     any information from the raw output, and hidden material can therefore
%     be viewed by direct examination of the file.
%   \end{texnote}
% \end{function}
%
% \begin{function}[added = 2019-01-23]
%   {
%     \box_set_trim:Nnnnn, \box_set_trim:cnnnn,
%     \box_gset_trim:Nnnnn, \box_gset_trim:cnnnn
%   }
%   \begin{syntax}
%     \cs{box_set_trim:Nnnnn} \meta{box} \Arg{left} \Arg{bottom} \Arg{right} \Arg{top}
%   \end{syntax}
%   Adjusts the bounding box of the \meta{box}: \meta{left} is removed from
%   the left-hand edge of the bounding box, \meta{right} from the right-hand
%   edge, and so forth. All adjustments are \meta{dim exprs}.
%   Material outside of the bounding box is still displayed in the output
%   unless \cs{box_set_clipped:N} is subsequently applied.
%   The updated \meta{box} is an
%   hbox, irrespective of the nature of the \meta{box} before the trim
%   operation is applied.
%   Additional box levels are also generated by this operation.
%   The behavior of the operation where the trims requested is
%   greater than the size of the box is undefined.
% \end{function}
%
% \begin{function}[added = 2019-01-23]
%   {
%     \box_set_viewport:Nnnnn, \box_set_viewport:cnnnn,
%     \box_gset_viewport:Nnnnn, \box_gset_viewport:cnnnn
%   }
%   \begin{syntax}
%     \cs{box_set_viewport:Nnnnn} \meta{box} \Arg{llx} \Arg{lly} \Arg{urx} \Arg{ury}
%   \end{syntax}
%   Adjusts the bounding box of the \meta{box} such that it has lower-left
%   coordinates (\meta{llx}, \meta{lly}) and upper-right coordinates
%   (\meta{urx}, \meta{ury}). All four coordinate positions are
%   \meta{dim exprs}. Material outside of the bounding box is
%   still displayed in the output unless \cs{box_set_clipped:N} is
%   subsequently applied.
%   The updated \meta{box} is an
%   hbox, irrespective of the nature of the \meta{box} before the viewport
%   operation is applied.
%   Additional box levels are also generated by this operation.
% \end{function}
%
% \section{Primitive box conditionals}
%
% \begin{function}[EXP]{\if_hbox:N}
%   \begin{syntax}
%     \cs{if_hbox:N} \meta{box}
%     ~~\meta{true code}
%     \cs{else:}
%     ~~\meta{false code}
%     \cs{fi:}
%   \end{syntax}
%   Tests if \meta{box} is a horizontal box.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{ifhbox}.
%   \end{texnote}
% \end{function}
%
% \begin{function}[EXP]{\if_vbox:N}
%   \begin{syntax}
%     \cs{if_vbox:N} \meta{box}
%     ~~\meta{true code}
%     \cs{else:}
%     ~~\meta{false code}
%     \cs{fi:}
%   \end{syntax}
%   Tests if \meta{box} is a vertical box.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{ifvbox}.
%   \end{texnote}
% \end{function}
%
% \begin{function}[EXP]{\if_box_empty:N}
%   \begin{syntax}
%     \cs{if_box_empty:N} \meta{box}
%     ~~\meta{true code}
%     \cs{else:}
%     ~~\meta{false code}
%     \cs{fi:}
%   \end{syntax}
%   Tests if \meta{box} is an empty (void) box.
%   \begin{texnote}
%     This is the \TeX{} primitive \tn{ifvoid}.
%   \end{texnote}
% \end{function}
%
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3box} implementation}
%
%    \begin{macrocode}
%<*code>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=box>
%    \end{macrocode}
%
% \subsection{Support code}
%
% \begin{macro}{\@@_dim_eval:w}
% \begin{macro}{\@@_dim_eval:n}
%   Evaluating a dimension expression expandably. The only
%   difference with \cs{dim_eval:n} is the lack of \cs{dim_use:N}, to
%   produce an internal dimension rather than expand it into characters.
%    \begin{macrocode}
\cs_new_eq:NN \@@_dim_eval:w \tex_dimexpr:D
\cs_new:Npn \@@_dim_eval:n #1
  { \@@_dim_eval:w #1 \scan_stop: }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Creating and initializing boxes}
%
% \TestFiles{m3box001.lvt}
%
% \begin{macro}{\box_new:N, \box_new:c}
%   Defining a new \meta{box} register: remember that box $255$ is not
%   generally available.
%    \begin{macrocode}
\cs_new_protected:Npn \box_new:N #1
  {
    \__kernel_chk_if_free_cs:N #1
    \cs:w newbox \cs_end: #1
  }
\cs_generate_variant:Nn \box_new:N { c }
%    \end{macrocode}
%
% \begin{macro}{\box_clear:N, \box_clear:c}
% \begin{macro}{\box_gclear:N, \box_gclear:c}
% \testfile*
%   Clear a \meta{box} register.
%    \begin{macrocode}
\cs_new_protected:Npn \box_clear:N #1
  { \box_set_eq:NN  #1 \c_empty_box }
\cs_new_protected:Npn \box_gclear:N #1
  { \box_gset_eq:NN #1 \c_empty_box }
\cs_generate_variant:Nn \box_clear:N  { c }
\cs_generate_variant:Nn \box_gclear:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\box_clear_new:N, \box_clear_new:c}
% \begin{macro}{\box_gclear_new:N, \box_gclear_new:c}
% \testfile*
%   Clear or new.
%    \begin{macrocode}
\cs_new_protected:Npn \box_clear_new:N #1
  { \box_if_exist:NTF #1 { \box_clear:N #1 } { \box_new:N #1 } }
\cs_new_protected:Npn \box_gclear_new:N #1
  { \box_if_exist:NTF #1 { \box_gclear:N #1 } { \box_new:N #1 } }
\cs_generate_variant:Nn \box_clear_new:N  { c }
\cs_generate_variant:Nn \box_gclear_new:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%  \begin{macro}
%    {\box_set_eq:NN, \box_set_eq:cN, \box_set_eq:Nc, \box_set_eq:cc}
% \testfile*
%  \begin{macro}
%    {\box_gset_eq:NN, \box_gset_eq:cN, \box_gset_eq:Nc, \box_gset_eq:cc}
% \testfile*
%   Assigning the contents of a box to be another box.
%    \begin{macrocode}
\cs_new_protected:Npn \box_set_eq:NN #1#2
  { \tex_setbox:D #1 \tex_copy:D #2 }
\cs_new_protected:Npn \box_gset_eq:NN #1#2
  { \tex_global:D \tex_setbox:D #1 \tex_copy:D #2 }
\cs_generate_variant:Nn \box_set_eq:NN  { c , Nc , cc }
\cs_generate_variant:Nn \box_gset_eq:NN { c , Nc , cc }
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
% \begin{macro}
%   {
%     \box_set_eq_drop:NN, \box_set_eq_drop:cN,
%     \box_set_eq_drop:Nc, \box_set_eq_drop:cc
%   }
% \begin{macro}
%   {
%     \box_gset_eq_drop:NN, \box_gset_eq_drop:cN,
%     \box_gset_eq_drop:Nc, \box_gset_eq_drop:cc
%   }
%    Assigning the contents of a box to be another box, then drops the
%    original box.
%    \begin{macrocode}
\cs_new_protected:Npn \box_set_eq_drop:NN #1#2
  { \tex_setbox:D #1 \tex_box:D #2 }
\cs_new_protected:Npn \box_gset_eq_drop:NN #1#2
  { \tex_global:D \tex_setbox:D #1 \tex_box:D #2 }
\cs_generate_variant:Nn \box_set_eq_drop:NN  { c , Nc , cc }
\cs_generate_variant:Nn \box_gset_eq_drop:NN { c , Nc , cc }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\box_if_exist:N, \box_if_exist:c}
%   Copies of the \texttt{cs} functions defined in \pkg{l3basics}.
%    \begin{macrocode}
\prg_new_eq_conditional:NNn \box_if_exist:N \cs_if_exist:N
  { TF , T , F , p }
\prg_new_eq_conditional:NNn \box_if_exist:c \cs_if_exist:c
  { TF , T , F , p }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Measuring and setting box dimensions}
%
% \begin{macro}{\box_ht:N, \box_ht:c}
% \begin{macro}{\box_dp:N, \box_dp:c}
% \begin{macro}{\box_wd:N, \box_wd:c}
% \testfile*
%    Accessing the height, depth, and width of a \meta{box} register.
%    \begin{macrocode}
\cs_new_eq:NN \box_ht:N \tex_ht:D
\cs_new_eq:NN \box_dp:N \tex_dp:D
\cs_new_eq:NN \box_wd:N \tex_wd:D
\cs_generate_variant:Nn \box_ht:N { c }
\cs_generate_variant:Nn \box_dp:N { c }
\cs_generate_variant:Nn \box_wd:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\box_ht_plus_dp:N}
%   The \cs{box_ht:N} and \cs{box_dp:N} primitives do not expand but
%   rather are suitable for use after \tn{the} or inside dimension
%   expressions.  Here we obtain the same behavior by using
%   \cs{@@_dim_eval:n} (basically \tn{dimexpr}) rather than
%   \cs{dim_eval:n} (basically \tn{the} \tn{dimexpr}).
%    \begin{macrocode}
\cs_new_protected:Npn \box_ht_plus_dp:N #1
  { \@@_dim_eval:n { \box_ht:N #1 + \box_dp:N #1 } }
\cs_generate_variant:Nn \box_ht_plus_dp:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\box_set_ht:Nn, \box_set_ht:cn, \box_gset_ht:Nn, \box_gset_ht:cn}
% \begin{macro}{\box_set_dp:Nn, \box_set_dp:cn, \box_gset_dp:Nn, \box_gset_dp:cn}
% \begin{macro}{\box_set_wd:Nn, \box_set_wd:cn, \box_gset_wd:Nn, \box_gset_wd:cn}
%   Setting the size whilst respecting local scope requires copying;
%   the same issue does not come up when working globally.
%   When debugging, the dimension expression |#2| is surrounded by
%   parentheses to catch early termination.
%    \begin{macrocode}
\cs_new_protected:Npn \box_set_dp:Nn #1#2
  {
    \tex_setbox:D #1 = \tex_copy:D #1
    \box_dp:N #1 \@@_dim_eval:n {#2}
  }
\cs_generate_variant:Nn \box_set_dp:Nn { c }
\cs_new_protected:Npn \box_gset_dp:Nn #1#2
  { \box_dp:N #1 \@@_dim_eval:n {#2} }
\cs_generate_variant:Nn \box_gset_dp:Nn { c }
\cs_new_protected:Npn \box_set_ht:Nn #1#2
  {
    \tex_setbox:D #1 = \tex_copy:D #1
    \box_ht:N #1 \@@_dim_eval:n {#2}
  }
\cs_generate_variant:Nn \box_set_ht:Nn { c }
\cs_new_protected:Npn \box_gset_ht:Nn #1#2
  { \box_ht:N #1 \@@_dim_eval:n {#2} }
\cs_generate_variant:Nn \box_gset_ht:Nn { c }
\cs_new_protected:Npn \box_set_wd:Nn #1#2
  {
    \tex_setbox:D #1 = \tex_copy:D #1
    \box_wd:N #1 \@@_dim_eval:n {#2}
  }
\cs_generate_variant:Nn \box_set_wd:Nn { c }
\cs_new_protected:Npn \box_gset_wd:Nn #1#2
  { \box_wd:N #1 \@@_dim_eval:n {#2} }
\cs_generate_variant:Nn \box_gset_wd:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \subsection{Using boxes}
%
% \begin{macro}{\box_use_drop:N, \box_use_drop:c}
% \begin{macro}{\box_use:N, \box_use:c}
%   Using a \meta{box}. These are just \TeX{} primitives with meaningful
%   names.
%    \begin{macrocode}
\cs_new_eq:NN \box_use_drop:N \tex_box:D
\cs_new_eq:NN \box_use:N \tex_copy:D
\cs_generate_variant:Nn \box_use_drop:N { c }
\cs_generate_variant:Nn \box_use:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\box_move_left:nn, \box_move_right:nn}
% \begin{macro}{\box_move_up:nn, \box_move_down:nn}
% \testfile*
%   Move box material in different directions.
%   When debugging, the dimension expression |#1| is surrounded by
%   parentheses to catch early termination.
%    \begin{macrocode}
\cs_new_protected:Npn \box_move_left:nn #1#2
  { \tex_moveleft:D \@@_dim_eval:n {#1} #2 }
\cs_new_protected:Npn \box_move_right:nn #1#2
  { \tex_moveright:D \@@_dim_eval:n {#1} #2 }
\cs_new_protected:Npn \box_move_up:nn #1#2
  { \tex_raise:D \@@_dim_eval:n {#1} #2 }
\cs_new_protected:Npn \box_move_down:nn #1#2
  { \tex_lower:D \@@_dim_eval:n {#1} #2 }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Box conditionals}
%
% \begin{macro}{\if_hbox:N}
% \begin{macro}{\if_vbox:N}
% \begin{macro}{\if_box_empty:N}
%  \testfile*
%    The primitives for testing if a \meta{box} is empty/void or which
%    type of box it is.
%    \begin{macrocode}
\cs_new_eq:NN \if_hbox:N      \tex_ifhbox:D
\cs_new_eq:NN \if_vbox:N      \tex_ifvbox:D
\cs_new_eq:NN \if_box_empty:N \tex_ifvoid:D
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\box_if_horizontal:N, \box_if_horizontal:c}
% \testfile*
% \begin{macro}[pTF]{\box_if_vertical:N, \box_if_vertical:c}
% \testfile*
%    \begin{macrocode}
\prg_new_conditional:Npnn \box_if_horizontal:N #1 { p , T , F , TF }
  { \if_hbox:N #1 \prg_return_true: \else: \prg_return_false: \fi: }
\prg_new_conditional:Npnn \box_if_vertical:N #1 { p , T , F , TF }
  { \if_vbox:N #1 \prg_return_true: \else: \prg_return_false: \fi: }
\prg_generate_conditional_variant:Nnn \box_if_horizontal:N
  { c } { p , T , F , TF }
\prg_generate_conditional_variant:Nnn \box_if_vertical:N
  { c } { p , T , F , TF }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}[pTF]{\box_if_empty:N, \box_if_empty:c}
% \testfile*
%   Testing if a \meta{box} is empty/void.
%    \begin{macrocode}
\prg_new_conditional:Npnn \box_if_empty:N #1 { p , T , F , TF }
  { \if_box_empty:N #1 \prg_return_true: \else: \prg_return_false: \fi: }
\prg_generate_conditional_variant:Nnn \box_if_empty:N
  { c } { p , T , F , TF }
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
% \subsection{The last box inserted}
%
% \begin{macro}{\box_set_to_last:N, \box_set_to_last:c}
% \begin{macro}{\box_gset_to_last:N, \box_gset_to_last:c}
% \testfile*
%    Set a box to the previous box.
%    \begin{macrocode}
\cs_new_protected:Npn \box_set_to_last:N #1
  { \tex_setbox:D #1 \tex_lastbox:D }
\cs_new_protected:Npn \box_gset_to_last:N #1
  { \tex_global:D \tex_setbox:D #1 \tex_lastbox:D }
\cs_generate_variant:Nn \box_set_to_last:N  { c }
\cs_generate_variant:Nn \box_gset_to_last:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Constant boxes}
%
% \begin{variable}{\c_empty_box}
%  A box we never use.
%    \begin{macrocode}
\box_new:N \c_empty_box
%    \end{macrocode}
% \end{variable}
%
% \subsection{Scratch boxes}
%
%  \begin{variable}{\l_tmpa_box, \l_tmpb_box, \g_tmpa_box, \g_tmpb_box}
%    Scratch boxes.
%    \begin{macrocode}
\box_new:N \l_tmpa_box
\box_new:N \l_tmpb_box
\box_new:N \g_tmpa_box
\box_new:N \g_tmpb_box
%    \end{macrocode}
% \end{variable}
%
% \subsection{Viewing box contents}
%
% \TeX{}'s \tn{showbox} is not really that helpful in many cases, and
% it is also inconsistent with other \LaTeX3{} \texttt{show} functions as it
% does not actually shows material in the terminal. So we provide a richer
% set of functionality.
%
% \begin{macro}{\box_show:N, \box_show:c}
% \begin{macro}{\box_show:Nnn, \box_show:cnn}
%   Essentially a wrapper around the internal function, but evaluating
%   the breadth and depth arguments now outside the group.
%    \begin{macrocode}
\cs_new_protected:Npn \box_show:N #1
  { \box_show:Nnn #1 \c_max_int \c_max_int }
\cs_generate_variant:Nn \box_show:N { c }
\cs_new_protected:Npn \box_show:Nnn #1#2#3
  { \@@_show:NNff 1 #1 { \int_eval:n {#2} } { \int_eval:n {#3} } }
\cs_generate_variant:Nn \box_show:Nnn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\box_log:N, \box_log:c}
% \begin{macro}{\box_log:Nnn, \box_log:cnn}
% \begin{macro}{\@@_log:nNnn}
%   Getting \TeX{} to write to the log without interruption the run is done by
%   altering the interaction mode. For that, the \eTeX{} extensions are needed.
%    \begin{macrocode}
\cs_new_protected:Npn \box_log:N #1
  { \box_log:Nnn #1 \c_max_int \c_max_int }
\cs_generate_variant:Nn \box_log:N { c }
\cs_new_protected:Npn \box_log:Nnn
  { \exp_args:No \@@_log:nNnn { \tex_the:D \tex_interactionmode:D } }
\cs_new_protected:Npn \@@_log:nNnn #1#2#3#4
  {
    \int_gset:Nn \tex_interactionmode:D { 0 }
    \@@_show:NNff 0 #2 { \int_eval:n {#3} } { \int_eval:n {#4} }
    \int_gset:Nn \tex_interactionmode:D {#1}
  }
\cs_generate_variant:Nn \box_log:Nnn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_show:NNnn, \@@_show:NNff}
%   The internal auxiliary to actually do the output uses a group to deal
%   with breadth and depth values. The \cs{use:n} here gives better output
%   appearance. Setting \tn{tracingonline} and \tn{errorcontextlines} is
%   used to control what appears in the terminal.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_show:NNnn #1#2#3#4
  {
    \box_if_exist:NTF #2
      {
        \group_begin:
          \int_set:Nn \tex_showboxbreadth:D {#3}
          \int_set:Nn \tex_showboxdepth:D   {#4}
          \int_set:Nn \tex_tracingonline:D  {#1}
          \int_set:Nn \tex_errorcontextlines:D { -1 }
          \tex_showbox:D \use:n {#2}
        \group_end:
      }
      {
        \msg_error:nne { kernel } { variable-not-defined }
          { \token_to_str:N #2 }
      }
  }
\cs_generate_variant:Nn \@@_show:NNnn { NNff }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Horizontal mode boxes}
%
% \begin{macro}{\hbox:n}
% \testfile{m3box002.lvt}
%   Put a horizontal box directly into the input stream.
%    \begin{macrocode}
\cs_new_protected:Npn \hbox:n #1
  { \tex_hbox:D \scan_stop: { \color_group_begin: #1 \color_group_end: } }
%    \end{macrocode}
%  \end{macro}
%
% \begin{macro}{\hbox_set:Nn, \hbox_set:cn}
% \begin{macro}{\hbox_gset:Nn, \hbox_gset:cn}
% \testfile*
%    \begin{macrocode}
\cs_new_protected:Npn \hbox_set:Nn #1#2
  {
    \tex_setbox:D #1 \tex_hbox:D
      { \color_group_begin: #2 \color_group_end: }
  }
\cs_new_protected:Npn \hbox_gset:Nn #1#2
  {
    \tex_global:D \tex_setbox:D #1 \tex_hbox:D
      { \color_group_begin: #2 \color_group_end: }
  }
\cs_generate_variant:Nn \hbox_set:Nn { c }
\cs_generate_variant:Nn \hbox_gset:Nn { c }
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
% \begin{macro}{\hbox_set_to_wd:Nnn, \hbox_set_to_wd:cnn}
% \begin{macro}{\hbox_gset_to_wd:Nnn, \hbox_gset_to_wd:cnn}
% \testfile*
%   Storing material in a horizontal box with a specified width.
%   Again, put the dimension expression in parentheses when debugging.
%    \begin{macrocode}
\cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3
  {
    \tex_setbox:D #1 \tex_hbox:D to \@@_dim_eval:n {#2}
      { \color_group_begin: #3 \color_group_end: }
  }
\cs_new_protected:Npn \hbox_gset_to_wd:Nnn #1#2#3
  {
    \tex_global:D \tex_setbox:D #1 \tex_hbox:D to \@@_dim_eval:n {#2}
      { \color_group_begin: #3 \color_group_end: }
  }
\cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c }
\cs_generate_variant:Nn \hbox_gset_to_wd:Nnn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\hbox_set:Nw, \hbox_set:cw}
% \begin{macro}{\hbox_gset:Nw, \hbox_gset:cw}
% \begin{macro}{\hbox_set_end:, \hbox_gset_end:}
% \testfile*
%    Storing material in a horizontal box. This type is useful in
%    environment definitions.
%    \begin{macrocode}
\cs_new_protected:Npn \hbox_set:Nw  #1
  {
    \tex_setbox:D #1 \tex_hbox:D
      \c_group_begin_token
        \color_group_begin:
  }
\cs_new_protected:Npn \hbox_gset:Nw  #1
  {
    \tex_global:D \tex_setbox:D #1 \tex_hbox:D
      \c_group_begin_token
        \color_group_begin:
  }
\cs_generate_variant:Nn \hbox_set:Nw  { c }
\cs_generate_variant:Nn \hbox_gset:Nw { c }
\cs_new_protected:Npn \hbox_set_end:
  {
      \color_group_end:
    \c_group_end_token
  }
\cs_new_eq:NN \hbox_gset_end: \hbox_set_end:
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\hbox_set_to_wd:Nnw, \hbox_set_to_wd:cnw}
% \begin{macro}{\hbox_gset_to_wd:Nnw, \hbox_gset_to_wd:cnw}
%   Combining the above ideas.
%    \begin{macrocode}
\cs_new_protected:Npn \hbox_set_to_wd:Nnw #1#2
  {
    \tex_setbox:D #1 \tex_hbox:D to \@@_dim_eval:n {#2}
      \c_group_begin_token
        \color_group_begin:
  }
\cs_new_protected:Npn \hbox_gset_to_wd:Nnw #1#2
  {
    \tex_global:D \tex_setbox:D #1 \tex_hbox:D to \@@_dim_eval:n {#2}
      \c_group_begin_token
        \color_group_begin:
  }
\cs_generate_variant:Nn \hbox_set_to_wd:Nnw  { c }
\cs_generate_variant:Nn \hbox_gset_to_wd:Nnw { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%  \begin{macro}{\hbox_to_wd:nn}
%  \begin{macro}{\hbox_to_zero:n}
%  \testfile*
%   Put a horizontal box directly into the input stream.
%    \begin{macrocode}
\cs_new_protected:Npn \hbox_to_wd:nn #1#2
  {
    \tex_hbox:D to \@@_dim_eval:n {#1}
      { \color_group_begin: #2 \color_group_end: }
  }
\cs_new_protected:Npn \hbox_to_zero:n #1
  {
    \tex_hbox:D to \c_zero_dim
      { \color_group_begin: #1 \color_group_end: }
  }
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
% \begin{macro}{\hbox_overlap_center:n, \hbox_overlap_left:n, \hbox_overlap_right:n}
%   Put a zero-sized box with the contents pushed against one side (which
%   makes it stick out on the other) directly into the input stream.
%    \begin{macrocode}
\cs_new_protected:Npn \hbox_overlap_center:n  #1
  { \hbox_to_zero:n { \tex_hss:D #1 \tex_hss:D } }
\cs_new_protected:Npn \hbox_overlap_left:n  #1
  { \hbox_to_zero:n { \tex_hss:D #1 } }
\cs_new_protected:Npn \hbox_overlap_right:n #1
  { \hbox_to_zero:n { #1 \tex_hss:D } }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\hbox_unpack:N, \hbox_unpack:c}
% \begin{macro}{\hbox_unpack_drop:N, \hbox_unpack_drop:c}
% \testfile*
%   Unpacking a box and if requested also clear it.
%    \begin{macrocode}
\cs_new_eq:NN \hbox_unpack:N \tex_unhcopy:D
\cs_new_eq:NN \hbox_unpack_drop:N \tex_unhbox:D
\cs_generate_variant:Nn \hbox_unpack:N { c }
\cs_generate_variant:Nn \hbox_unpack_drop:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Vertical mode boxes}
%
% \TeX{} ends these boxes directly with the internal \emph{end_graf}
% routine. This means that there is no \cs{par} at the end of vertical
% boxes unless we insert one. Thus all vertical boxes include a \cs{par}
% just before closing the color group.
%
% \begin{macro}{\vbox:n, \vbox_top:n}
% \begin{macro}{\vbox:w, \vbox_top:w}
% \begin{macro}{\vbox_end:}
%   Put a vertical box directly into the input stream.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox:n #1
  { \tex_vbox:D { \color_group_begin: #1 \par \color_group_end: } }
\cs_new_protected:Npn \vbox_top:n #1
  { \tex_vtop:D { \color_group_begin: #1 \par \color_group_end: } }
\cs_new_protected:Npn \vbox:w
  { \tex_vbox:D \c_group_begin_token \color_group_begin: }
\cs_new_protected:Npn \vbox_top:w
  { \tex_vtop:D \c_group_begin_token \color_group_begin: }
\cs_new_protected:Npn \vbox_end:
  {
        \par
      \color_group_end:
    \c_group_end_token
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{variable}{\l_@@_delta_dim, \l_@@_voffset_dim}
%   Needed for the vertical centering calc.
%    \begin{macrocode}
\dim_new:N \l_@@_delta_dim
\dim_new:N \l_@@_voffset_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\vbox_center:nw}
% \begin{macro}{\vbox_center:w}
% \begin{macro}{\vbox_center_to_ht:nw}
% \begin{macro}{\@@_vcenter:nnw}
% \begin{macro}{\@@_vcenter_aux:}
% \begin{macro}{\vbox_center:nn}
% \begin{macro}{\vbox_center:n}
% \begin{macro}{\vbox_center_to_ht:nn}
% \begin{macro}{\@@_vcenter:Nnnn}
% \begin{macro}{\@@_vcenter_calc:n}
%   This is set up first as the |:nw|/|:nn| version as that's \emph{required}
%   to implement the |:n| one; contrast with the other two vertical
%   placements, where we start with the simple case then build the more involved
%   one. To avoid reading content multiple times, we use two internals for the
%   |w| and |n| versions, then use a common auxiliary at the calculation stage.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox_center:nw
  { \@@_vcenter:nnw { } }
\cs_new_protected:Npn \vbox_center:w
  { \@@_vcenter:nnw { } \c_zero_dim }
\cs_new_protected:Npn \vbox_center_to_ht:nw #1
  { \@@_vcenter:nnw { to \@@_dim_eval:n {#1} } \c_zero_dim }
%    \end{macrocode}
%   Starting the box with \cs{c_group_begin_token} avoids needing
%   \tn{afterassignment} to get the end-of-group tokens in the correct
%   place.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_vcenter:nnw #1#2
  {
    \dim_set:Nn \l_@@_voffset_dim {#2}
    \tex_setbox:D \l_@@_tmp_box \tex_vbox:D #1
      \c_group_begin_token
        \group_insert_after:N \@@_vcenter_aux:
        \color_group_begin:
  }
\cs_new_protected:Npn \@@_vcenter_aux:
  { \@@_vcenter_calc:n \l_@@_voffset_dim }
\cs_new_protected:Npn \vbox_center:nn
  { \@@_vcenter:Nnnn \vbox_set:Nn { } }
\cs_new_protected:Npn \vbox_center:n
  { \@@_vcenter:Nnnn \vbox_set:Nn { } \c_zero_dim }
\cs_new_protected:Npn \vbox_center_to_ht:nn #1
  { \@@_vcenter:Nnnn \vbox_set_to_ht:Nnn { {#1} } \c_zero_dim }
\cs_new_protected:Npn \@@_vcenter:Nnnn #1#2#3#4
  {
    #1 \l_@@_tmp_box #2 {#4}
    \@@_vcenter_calc:n {#3}
  }
%    \end{macrocode}
%   To get exactly the same outcomes as \tn{vcenter}, we need to implement
%   \emph{exactly} the approach used in \texttt{tex.web}:
%   \begin{Verbatim}[gobble = 5]
%     delta:=height(v)+depth(v);
%     height(v):=axis_height(cur_size)+half(delta);
%     depth(v):=delta-height(v);
%   \end{Verbatim}
%   where
%   \begin{Verbatim}[gobble = 5]
%     @p function half(@!x:integer):integer;
%     begin if odd(x) then half:=(x+1) div 2
%     else half:=x @!div 2;
%     end;
%   \end{Verbatim}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_vcenter_calc:n #1
  {
    \dim_set:Nn \l_@@_delta_dim
      { \box_ht:N \l_@@_tmp_box + \box_dp:N \l_@@_tmp_box }
    \tex_ht:D \l_@@_tmp_box \@@_dim_eval:n
      {
        \@@_dim_eval:n
          { \tex_ifodd:D \l_@@_delta_dim 1sp + \tex_fi:D \l_@@_delta_dim }
        / 2
        + (#1)
      }
    \tex_dp:D \l_@@_tmp_box \@@_dim_eval:n
      { \l_@@_delta_dim - \box_ht:N \l_@@_tmp_box }
    \box_use_drop:N \l_@@_tmp_box
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vbox_to_ht:nn, \vbox_top_to_ht:nn}
% \begin{macro}{\@@_to_ht:Nnn}
% \begin{macro}{\vbox_to_ht:nw, \vbox_top_to_ht:nw}
% \begin{macro}{\@@_to_ht:Nnw}
% \begin{macro}{\vbox_to_zero:n}
% \testfile*
%   Put a vertical box directly into the input stream.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox_to_ht:nn #1#2
  { \@@_to_ht:Nnn \tex_vbox:D {#1} {#2} }
\cs_new_protected:Npn \vbox_top_to_ht:nn #1#2
  { \@@_to_ht:Nnn \tex_vtop:D {#1} {#2} }
\cs_new_protected:Npn \@@_to_ht:Nnn #1#2#3
  {
    #1 to \@@_dim_eval:n {#2}
      { \color_group_begin: #3 \par \color_group_end: }
  }
\cs_new_protected:Npn \vbox_to_ht:nw #1
  { \@@_to_ht:Nnw \tex_vbox:D {#1} }
\cs_new_protected:Npn \vbox_top_to_ht:nw #1
  { \@@_to_ht:Nnw \tex_vtop:D {#1} }
\cs_new_protected:Npn \@@_to_ht:Nnw #1#2
  {
    #1 to \@@_dim_eval:n {#2}
      \c_group_begin_token
        \color_group_begin:
  }
\cs_new_protected:Npn \vbox_to_zero:n #1
  { \vbox_to_ht:nn { 0pt } {#1} }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vbox:nw, \vbox_top:nw}
% \begin{macro}{\@@_voffset:Nnnw}
% \begin{macro}{\@@_voffset_aux:}
% \begin{macro}{\vbox:nn, \vbox_top:nn}
% \begin{macro}{\@@_voffset:Nnnn}
% \begin{macro}{\@@_voffset_calc:n}
%   Mainly for consistency of language.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox:nw
  { \@@_voffset:Nnnw \tex_vbox:D { } }
\cs_new_protected:Npn \vbox_top:nw
  { \@@_voffset:Nnnw \tex_vtop:D { } }
\cs_new_protected:Npn \@@_voffset:Nnnw #1#2#3
  {
    \dim_set:Nn \l_@@_voffset_dim {#3}
    \tex_setbox:D \l_@@_tmp_box #1 #2
      \c_group_begin_token
        \group_insert_after:N \@@_voffset_aux:
        \color_group_begin:
  }
\cs_new_protected:Npn \@@_voffset_aux:
  { \@@_voffset_calc:n \l_@@_voffset_dim }
\cs_new_protected:Npn \vbox:nn
  { \@@_voffset:Nnnn \vbox_set:Nn { } }
\cs_new_protected:Npn \vbox_top:nn
  { \@@_voffset:Nnnn \vbox_set_top:Nn { } }
\cs_new_protected:Npn \@@_voffset:Nnnn #1#2#3#4
  {
    #1 \l_@@_tmp_box #2 {#4}
    \@@_voffset_calc:n {#3}
  }
\cs_new_protected:Npn \@@_voffset_calc:n #1
  {
    \box_set_ht:Nn \l_@@_tmp_box
      { \box_ht:N \l_@@_tmp_box + (#1) }
    \box_set_dp:Nn \l_@@_tmp_box
      { \box_dp:N \l_@@_tmp_box - (#1) }
    \box_use_drop:N \l_@@_tmp_box
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vbox_set:Nn, \vbox_set:cn}
% \begin{macro}{\vbox_gset:Nn, \vbox_gset:cn}
% \testfile*
%   Storing material in a vertical box with a natural height.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox_set:Nn #1#2
  {
    \tex_setbox:D #1 \tex_vbox:D
      { \color_group_begin: #2 \par \color_group_end: }
  }
\cs_new_protected:Npn \vbox_gset:Nn #1#2
  {
    \tex_global:D \tex_setbox:D #1 \tex_vbox:D
      { \color_group_begin: #2 \par \color_group_end: }
  }
\cs_generate_variant:Nn \vbox_set:Nn  { c }
\cs_generate_variant:Nn \vbox_gset:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vbox_set_top:Nn, \vbox_set_top:cn}
% \begin{macro}{\vbox_gset_top:Nn, \vbox_gset_top:cn}
% \testfile*
%   Storing material in a vertical box with a natural height and reference
%   point at the baseline of the first object in the box.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox_set_top:Nn #1#2
  {
    \tex_setbox:D #1 \tex_vtop:D
      { \color_group_begin: #2 \par \color_group_end: }
  }
\cs_new_protected:Npn \vbox_gset_top:Nn #1#2
  {
    \tex_global:D \tex_setbox:D #1 \tex_vtop:D
      { \color_group_begin: #2 \par \color_group_end: }
  }
\cs_generate_variant:Nn \vbox_set_top:Nn { c }
\cs_generate_variant:Nn \vbox_gset_top:Nn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vbox_set_to_ht:Nnn, \vbox_set_to_ht:cnn}
% \begin{macro}{\vbox_gset_to_ht:Nnn, \vbox_gset_to_ht:cnn}
%  \testfile*
%    \begin{macrocode}
\cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3
  {
    \tex_setbox:D #1 \tex_vbox:D to \@@_dim_eval:n {#2}
      { \color_group_begin: #3 \par \color_group_end: }
  }
\cs_new_protected:Npn \vbox_gset_to_ht:Nnn #1#2#3
  {
    \tex_global:D \tex_setbox:D #1 \tex_vbox:D to \@@_dim_eval:n {#2}
      { \color_group_begin: #3 \par \color_group_end: }
  }
\cs_generate_variant:Nn \vbox_set_to_ht:Nnn  { c }
\cs_generate_variant:Nn \vbox_gset_to_ht:Nnn { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vbox_set:Nw, \vbox_set:cw}
% \begin{macro}{\vbox_gset:Nw, \vbox_gset:cw}
% \begin{macro}{\vbox_set_end:, \vbox_gset_end:}
% \testfile*
%   Storing material in a vertical box. This type is useful in
%   environment definitions.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox_set:Nw #1
  {
    \tex_setbox:D #1 \tex_vbox:D
      \c_group_begin_token
        \color_group_begin:
  }
\cs_new_protected:Npn \vbox_gset:Nw #1
  {
    \tex_global:D \tex_setbox:D #1 \tex_vbox:D
      \c_group_begin_token
        \color_group_begin:
  }
\cs_generate_variant:Nn \vbox_set:Nw  { c }
\cs_generate_variant:Nn \vbox_gset:Nw { c }
\cs_new_eq:NN \vbox_set_end: \vbox_end:
\cs_new_eq:NN \vbox_gset_end: \vbox_end:
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vbox_set_to_ht:Nnw, \vbox_set_to_ht:cnw}
% \begin{macro}{\vbox_gset_to_ht:Nnw, \vbox_gset_to_ht:cnw}
%   A combination of the above ideas.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox_set_to_ht:Nnw #1#2
  {
    \tex_setbox:D #1 \tex_vbox:D to \@@_dim_eval:n {#2}
      \c_group_begin_token
        \color_group_begin:
  }
\cs_new_protected:Npn \vbox_gset_to_ht:Nnw #1#2
  {
    \tex_global:D \tex_setbox:D #1 \tex_vbox:D to \@@_dim_eval:n {#2}
      \c_group_begin_token
        \color_group_begin:
  }
\cs_generate_variant:Nn \vbox_set_to_ht:Nnw  { c }
\cs_generate_variant:Nn \vbox_gset_to_ht:Nnw { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\vbox_unpack:N, \vbox_unpack:c}
% \begin{macro}{\vbox_unpack_drop:N, \vbox_unpack_drop:c}
% \testfile*
%   Unpacking a box and if requested also clear it.
%    \begin{macrocode}
\cs_new_eq:NN \vbox_unpack:N \tex_unvcopy:D
\cs_new_eq:NN \vbox_unpack_drop:N \tex_unvbox:D
\cs_generate_variant:Nn \vbox_unpack:N { c }
\cs_generate_variant:Nn \vbox_unpack_drop:N { c }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \vbox_set_split_to_ht:NNn, \vbox_set_split_to_ht:cNn,
%     \vbox_set_split_to_ht:Ncn, \vbox_set_split_to_ht:ccn,
%     \vbox_gset_split_to_ht:NNn, \vbox_gset_split_to_ht:cNn,
%     \vbox_gset_split_to_ht:Ncn, \vbox_gset_split_to_ht:ccn,
%   }
% \testfile*
%   Splitting a vertical box in two.
%    \begin{macrocode}
\cs_new_protected:Npn \vbox_set_split_to_ht:NNn #1#2#3
  { \tex_setbox:D #1 \tex_vsplit:D #2 to \@@_dim_eval:n {#3} }
\cs_generate_variant:Nn \vbox_set_split_to_ht:NNn { c , Nc , cc }
\cs_new_protected:Npn \vbox_gset_split_to_ht:NNn #1#2#3
  {
    \tex_global:D \tex_setbox:D #1
      \tex_vsplit:D #2 to \@@_dim_eval:n {#3}
  }
\cs_generate_variant:Nn \vbox_gset_split_to_ht:NNn { c , Nc , cc }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Affine transformations}
%
% \begin{variable}{\l_@@_angle_fp}
%   When rotating boxes, the angle itself may be needed by the
%   engine-dependent code. This is done using the \pkg{fp} module so
%   that the value is tidied up properly.
%    \begin{macrocode}
\fp_new:N \l_@@_angle_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_cos_fp, \l_@@_sin_fp}
%   These are used to hold the calculated sine and cosine values while
%   carrying out a rotation.
%    \begin{macrocode}
\fp_new:N \l_@@_cos_fp
\fp_new:N \l_@@_sin_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%   {\l_@@_top_dim, \l_@@_bottom_dim, \l_@@_left_dim, \l_@@_right_dim}
%   These are the positions of the four edges of a box before
%   manipulation.
%    \begin{macrocode}
\dim_new:N \l_@@_top_dim
\dim_new:N \l_@@_bottom_dim
\dim_new:N \l_@@_left_dim
\dim_new:N \l_@@_right_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}
%  {
%    \l_@@_top_new_dim,  \l_@@_bottom_new_dim ,
%    \l_@@_left_new_dim, \l_@@_right_new_dim
%  }
%   These are the positions of the four edges of a box after
%   manipulation.
%    \begin{macrocode}
\dim_new:N \l_@@_top_new_dim
\dim_new:N \l_@@_bottom_new_dim
\dim_new:N \l_@@_left_new_dim
\dim_new:N \l_@@_right_new_dim
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_tmp_box}
%   Scratch space, but also needed by some parts of the driver.
%    \begin{macrocode}
\box_new:N \l_@@_tmp_box
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}
%   {
%     \box_rotate:Nn, \box_rotate:cn,
%     \box_grotate:Nn, \box_grotate:cn
%   }
% \begin{macro}{\@@_rotate:NnN}
% \begin{macro}{\@@_rotate:N}
% \begin{macro}{\@@_rotate_xdir:nnN, \@@_rotate_ydir:nnN}
% \begin{macro}
%   {
%     \@@_rotate_quadrant_one:,   \@@_rotate_quadrant_two:,
%     \@@_rotate_quadrant_three:, \@@_rotate_quadrant_four:
%   }
%   Rotation of a box starts with working out the relevant sine and
%   cosine. The actual rotation is in an auxiliary to keep the flow slightly
%   clearer
%    \begin{macrocode}
\cs_new_protected:Npn \box_rotate:Nn #1#2
  { \@@_rotate:NnN #1 {#2} \hbox_set:Nn }
\cs_generate_variant:Nn \box_rotate:Nn { c }
\cs_new_protected:Npn \box_grotate:Nn #1#2
  { \@@_rotate:NnN #1 {#2} \hbox_gset:Nn }
\cs_generate_variant:Nn \box_grotate:Nn { c }
\cs_new_protected:Npn \@@_rotate:NnN #1#2#3
  {
    #3 #1
      {
        \fp_set:Nn \l_@@_angle_fp {#2}
        \fp_set:Nn \l_@@_sin_fp { sind ( \l_@@_angle_fp ) }
        \fp_set:Nn \l_@@_cos_fp { cosd ( \l_@@_angle_fp ) }
        \@@_rotate:N #1
      }
  }
%    \end{macrocode}
%   The edges of the box are then recorded: the left edge is
%   always at zero. Rotation of the four edges then takes place: this is
%   most efficiently done on a quadrant by quadrant basis.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate:N #1
  {
    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
    \dim_zero:N \l_@@_left_dim
%    \end{macrocode}
%   The next step is to work out the $x$ and $y$ coordinates of vertices of
%   the rotated box in relation to its original coordinates. The box can be
%   visualized with vertices $B$, $C$, $D$ and $E$ is illustrated
%   (Figure~\ref{fig:l3box:rotation}). The vertex $O$ is the reference point
%   on the baseline, and in this implementation is also the center of rotation.
%   \begin{figure}
%     \centering
%     \setlength{\unitlength}{3pt}^^A
%     \begin{picture}(34,36)(12,44)
%       \thicklines
%       \put(20,52){\dashbox{1}(20,21){}}
%       \put(20,80){\line(0,-1){36}}
%       \put(12,58){\line(1, 0){34}}
%       \put(41,59){A}
%       \put(40,74){B}
%       \put(21,74){C}
%       \put(21,49){D}
%       \put(40,49){E}
%       \put(21,59){O}
%     \end{picture}
%     \caption{Coordinates of a box prior to rotation.}
%     \label{fig:l3box:rotation}
%   \end{figure}
%   The formulae are, for a point $P$ and angle $\alpha$:
%   \[
%     \begin{array}{l}
%       P'_x = P_x - O_x \\
%       P'_y = P_y - O_y \\
%       P''_x =  ( P'_x \cos(\alpha)) - ( P'_y \sin(\alpha) ) \\
%       P''_y =  ( P'_x \sin(\alpha)) + ( P'_y \cos(\alpha) ) \\
%       P'''_x = P''_x + O_x + L_x \\
%       P'''_y = P''_y + O_y
%    \end{array}
%   \]
%   The \enquote{extra} horizontal translation $L_x$ at the end is calculated
%   so that the leftmost point of the resulting box has $x$-coordinate $0$.
%   This is desirable as \TeX{} boxes must have the reference point at
%   the left edge of the box. (As $O$ is always $(0,0)$, this part of the
%   calculation is omitted here.)
%    \begin{macrocode}
    \fp_compare:nNnTF \l_@@_sin_fp > \c_zero_fp
      {
        \fp_compare:nNnTF \l_@@_cos_fp > \c_zero_fp
          { \@@_rotate_quadrant_one: }
          { \@@_rotate_quadrant_two: }
      }
      {
        \fp_compare:nNnTF \l_@@_cos_fp < \c_zero_fp
          { \@@_rotate_quadrant_three: }
          { \@@_rotate_quadrant_four: }
      }
%    \end{macrocode}
%   The position of the box edges are now known, but the box at this
%   stage be misplaced relative to the current \TeX{} reference point. So the
%   content of the box is moved such that the reference point of the
%   rotated box is in the same place as the original.
%    \begin{macrocode}
    \hbox_set:Nn \l_@@_tmp_box { \box_use:N #1 }
    \hbox_set:Nn \l_@@_tmp_box
      {
        \dim_horizontal:n { -\l_@@_left_new_dim }
        \hbox:n
          {
            \@@_backend_rotate:Nn
              \l_@@_tmp_box
              \l_@@_angle_fp
          }
      }
%    \end{macrocode}
%   Tidy up the size of the box so that the material is actually inside
%   the bounding box. The result can then be used to reset the original
%   box.
%    \begin{macrocode}
    \box_set_ht:Nn \l_@@_tmp_box {  \l_@@_top_new_dim }
    \box_set_dp:Nn \l_@@_tmp_box { -\l_@@_bottom_new_dim }
    \box_set_wd:Nn \l_@@_tmp_box
      { \l_@@_right_new_dim - \l_@@_left_new_dim }
    \box_use_drop:N \l_@@_tmp_box
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%   These functions take a general point $(|#1|, |#2|)$ and rotate its
%   location about the origin, using the previously-set sine and cosine
%   values. Each function gives only one component of the location of the
%   updated point. This is because for rotation of a box each step needs
%   only one value, and so performance is gained by avoiding working
%   out both $x'$ and $y'$ at the same time. Contrast this with
%   the equivalent function in the \pkg{l3coffins} module, where both parts
%   are needed.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate_xdir:nnN #1#2#3
  {
    \dim_set:Nn #3
      {
        \fp_to_dim:n
          {
              \l_@@_cos_fp * \dim_to_fp:n {#1}
            - \l_@@_sin_fp * \dim_to_fp:n {#2}
          }
      }
  }
\cs_new_protected:Npn \@@_rotate_ydir:nnN #1#2#3
  {
    \dim_set:Nn #3
      {
        \fp_to_dim:n
          {
              \l_@@_sin_fp * \dim_to_fp:n {#1}
            + \l_@@_cos_fp * \dim_to_fp:n {#2}
          }
      }
  }
%    \end{macrocode}
%   Rotation of the edges is done using a different formula for each
%   quadrant. In every case, the top and bottom edges only need the
%   resulting $y$-values, whereas the left and right edges need the
%   $x$-values. Each case is a question of picking out which corner
%   ends up at with the maximum top, bottom, left and right value. Doing
%   this by hand means a lot less calculating and avoids lots of
%   comparisons.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rotate_quadrant_one:
  {
    \@@_rotate_ydir:nnN \l_@@_right_dim \l_@@_top_dim
      \l_@@_top_new_dim
    \@@_rotate_ydir:nnN \l_@@_left_dim  \l_@@_bottom_dim
      \l_@@_bottom_new_dim
    \@@_rotate_xdir:nnN \l_@@_left_dim  \l_@@_top_dim
      \l_@@_left_new_dim
    \@@_rotate_xdir:nnN \l_@@_right_dim \l_@@_bottom_dim
      \l_@@_right_new_dim
  }
\cs_new_protected:Npn \@@_rotate_quadrant_two:
  {
    \@@_rotate_ydir:nnN \l_@@_right_dim \l_@@_bottom_dim
      \l_@@_top_new_dim
    \@@_rotate_ydir:nnN \l_@@_left_dim  \l_@@_top_dim
      \l_@@_bottom_new_dim
    \@@_rotate_xdir:nnN \l_@@_right_dim  \l_@@_top_dim
      \l_@@_left_new_dim
    \@@_rotate_xdir:nnN \l_@@_left_dim   \l_@@_bottom_dim
      \l_@@_right_new_dim
  }
\cs_new_protected:Npn \@@_rotate_quadrant_three:
  {
    \@@_rotate_ydir:nnN \l_@@_left_dim  \l_@@_bottom_dim
      \l_@@_top_new_dim
    \@@_rotate_ydir:nnN \l_@@_right_dim \l_@@_top_dim
      \l_@@_bottom_new_dim
    \@@_rotate_xdir:nnN \l_@@_right_dim \l_@@_bottom_dim
      \l_@@_left_new_dim
    \@@_rotate_xdir:nnN \l_@@_left_dim   \l_@@_top_dim
      \l_@@_right_new_dim
  }
\cs_new_protected:Npn \@@_rotate_quadrant_four:
  {
    \@@_rotate_ydir:nnN \l_@@_left_dim  \l_@@_top_dim
      \l_@@_top_new_dim
    \@@_rotate_ydir:nnN \l_@@_right_dim \l_@@_bottom_dim
      \l_@@_bottom_new_dim
    \@@_rotate_xdir:nnN \l_@@_left_dim  \l_@@_bottom_dim
      \l_@@_left_new_dim
    \@@_rotate_xdir:nnN \l_@@_right_dim \l_@@_top_dim
      \l_@@_right_new_dim
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{variable}{\l_@@_scale_x_fp, \l_@@_scale_y_fp}
%   Scaling is potentially-different in the two axes.
%    \begin{macrocode}
\fp_new:N \l_@@_scale_x_fp
\fp_new:N \l_@@_scale_y_fp
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}
%   {
%     \box_resize_to_wd_and_ht_plus_dp:Nnn,
%     \box_resize_to_wd_and_ht_plus_dp:cnn,
%     \box_gresize_to_wd_and_ht_plus_dp:Nnn,
%     \box_gresize_to_wd_and_ht_plus_dp:cnn
%   }
% \begin{macro}{\@@_resize_to_wd_and_ht_plus_dp:NnnN}
% \begin{macro}{\@@_resize_set_corners:N}
% \begin{macro}{\@@_resize:N}
% \begin{macro}{\@@_resize:NNN}
%   Resizing a box starts by working out the various dimensions of the
%   existing box.
%    \begin{macrocode}
\cs_new_protected:Npn \box_resize_to_wd_and_ht_plus_dp:Nnn #1#2#3
  {
    \@@_resize_to_wd_and_ht_plus_dp:NnnN #1 {#2} {#3}
      \hbox_set:Nn
  }
\cs_generate_variant:Nn \box_resize_to_wd_and_ht_plus_dp:Nnn { c }
\cs_new_protected:Npn \box_gresize_to_wd_and_ht_plus_dp:Nnn #1#2#3
  {
    \@@_resize_to_wd_and_ht_plus_dp:NnnN #1 {#2} {#3}
      \hbox_gset:Nn
  }
\cs_generate_variant:Nn \box_gresize_to_wd_and_ht_plus_dp:Nnn { c }
\cs_new_protected:Npn \@@_resize_to_wd_and_ht_plus_dp:NnnN #1#2#3#4
  {
    #4 #1
      {
        \@@_resize_set_corners:N #1
%    \end{macrocode}
%   The $x$-scaling and resulting box size is easy enough to work
%   out: the dimension is that given as |#2|, and the scale is simply the
%   new width divided by the old one.
%    \begin{macrocode}
        \fp_set:Nn \l_@@_scale_x_fp
          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
%    \end{macrocode}
%   The $y$-scaling needs both the height and the depth of the current box.
%    \begin{macrocode}
        \fp_set:Nn \l_@@_scale_y_fp
          {
              \dim_to_fp:n {#3}
            / \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim }
          }
%    \end{macrocode}
%   Hand off to the auxiliary which does the rest of the work.
%    \begin{macrocode}
        \@@_resize:N #1
      }
  }
\cs_new_protected:Npn \@@_resize_set_corners:N #1
  {
    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
    \dim_zero:N \l_@@_left_dim
  }
%    \end{macrocode}
%   With at least one real scaling to do, the next phase is to find the new
%   edge coordinates. In the $x$~direction this is relatively easy: just
%   scale the right edge. In the $y$~direction, both dimensions have to be
%   scaled, and this again needs the absolute scale value.
%   Once that is all done, the common resize/rescale code can be employed.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_resize:N #1
  {
    \@@_resize:NNN \l_@@_right_new_dim
      \l_@@_scale_x_fp \l_@@_right_dim
    \@@_resize:NNN \l_@@_bottom_new_dim
      \l_@@_scale_y_fp \l_@@_bottom_dim
    \@@_resize:NNN \l_@@_top_new_dim
      \l_@@_scale_y_fp \l_@@_top_dim
    \@@_resize_common:N #1
  }
\cs_new_protected:Npn \@@_resize:NNN #1#2#3
  {
    \dim_set:Nn #1
      { \fp_to_dim:n { \fp_abs:n { #2 } * \dim_to_fp:n { #3 } } }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_resize_to_ht:Nn, \box_resize_to_ht:cn,
%     \box_gresize_to_ht:Nn, \box_gresize_to_ht:cn
%   }
% \begin{macro}{\@@_resize_to_ht:NnN}
% \begin{macro}
%   {
%     \box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn,
%     \box_gresize_to_ht_plus_dp:Nn, \box_gresize_to_ht_plus_dp:cn
%   }
% \begin{macro}{\@@_resize_to_ht_plus_dp:NnN}
% \begin{macro}
%   {
%     \box_resize_to_wd:Nn, \box_resize_to_wd:cn,
%     \box_gresize_to_wd:Nn, \box_gresize_to_wd:cn
%   }
% \begin{macro}{\@@_resize_to_wd:NnN}
% \begin{macro}
%   {
%     \box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn,
%     \box_gresize_to_wd_and_ht:Nnn, \box_gresize_to_wd_and_ht:cnn
%   }
% \begin{macro}{\@@_resize_to_wd_ht:NnnN}
%   Scaling to a (total) height or to a width is a simplified version of the main
%   resizing operation, with the scale simply copied between the two parts. The
%   internal auxiliary is called using the scaling value twice, as the sign for
%   both parts is needed (as this allows the same internal code to be used as
%   for the general case).
%    \begin{macrocode}
\cs_new_protected:Npn \box_resize_to_ht:Nn #1#2
  { \@@_resize_to_ht:NnN #1 {#2} \hbox_set:Nn }
\cs_generate_variant:Nn \box_resize_to_ht:Nn { c }
\cs_new_protected:Npn \box_gresize_to_ht:Nn #1#2
  { \@@_resize_to_ht:NnN #1 {#2} \hbox_gset:Nn }
\cs_generate_variant:Nn \box_gresize_to_ht:Nn { c }
\cs_new_protected:Npn \@@_resize_to_ht:NnN #1#2#3
  {
    #3 #1
      {
        \@@_resize_set_corners:N #1
        \fp_set:Nn \l_@@_scale_y_fp
          {
              \dim_to_fp:n {#2}
            / \dim_to_fp:n { \l_@@_top_dim }
          }
        \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp
        \@@_resize:N #1
      }
  }
\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2
  { \@@_resize_to_ht_plus_dp:NnN #1 {#2} \hbox_set:Nn }
\cs_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c }
\cs_new_protected:Npn \box_gresize_to_ht_plus_dp:Nn #1#2
  { \@@_resize_to_ht_plus_dp:NnN #1 {#2} \hbox_gset:Nn }
\cs_generate_variant:Nn \box_gresize_to_ht_plus_dp:Nn { c }
\cs_new_protected:Npn \@@_resize_to_ht_plus_dp:NnN #1#2#3
  {
    #3 #1
      {
        \@@_resize_set_corners:N #1
        \fp_set:Nn \l_@@_scale_y_fp
          {
              \dim_to_fp:n {#2}
            / \dim_to_fp:n { \l_@@_top_dim - \l_@@_bottom_dim }
          }
        \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp
        \@@_resize:N #1
      }
  }
\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2
  { \@@_resize_to_wd:NnN #1 {#2} \hbox_set:Nn }
\cs_generate_variant:Nn \box_resize_to_wd:Nn { c }
\cs_new_protected:Npn \box_gresize_to_wd:Nn #1#2
  { \@@_resize_to_wd:NnN #1 {#2} \hbox_gset:Nn }
\cs_generate_variant:Nn \box_gresize_to_wd:Nn { c }
\cs_new_protected:Npn \@@_resize_to_wd:NnN #1#2#3
  {
    #3 #1
      {
        \@@_resize_set_corners:N #1
        \fp_set:Nn \l_@@_scale_x_fp
          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
        \fp_set_eq:NN \l_@@_scale_y_fp \l_@@_scale_x_fp
        \@@_resize:N #1
      }
  }
\cs_new_protected:Npn \box_resize_to_wd_and_ht:Nnn #1#2#3
  { \@@_resize_to_wd_and_ht:NnnN #1 {#2} {#3} \hbox_set:Nn }
\cs_generate_variant:Nn \box_resize_to_wd_and_ht:Nnn { c }
\cs_new_protected:Npn \box_gresize_to_wd_and_ht:Nnn #1#2#3
  { \@@_resize_to_wd_and_ht:NnnN #1 {#2} {#3} \hbox_gset:Nn }
\cs_generate_variant:Nn \box_gresize_to_wd_and_ht:Nnn { c }
\cs_new_protected:Npn \@@_resize_to_wd_and_ht:NnnN #1#2#3#4
  {
    #4 #1
      {
        \@@_resize_set_corners:N #1
        \fp_set:Nn \l_@@_scale_x_fp
          { \dim_to_fp:n {#2} / \dim_to_fp:n { \l_@@_right_dim } }
        \fp_set:Nn \l_@@_scale_y_fp
          {
              \dim_to_fp:n {#3}
            / \dim_to_fp:n { \l_@@_top_dim }
          }
        \@@_resize:N #1
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_scale:Nnn, \box_scale:cnn,
%     \box_gscale:Nnn, \box_gscale:cnn
%   }
% \begin{macro}{\@@_scale:NnnN}
% \begin{macro}{\@@_scale:N}
%   When scaling a box, setting the scaling itself is easy enough. The
%   new dimensions are also relatively easy to find, allowing only for
%   the need to keep them positive in all cases. Once that is done then
%   after a check for the trivial scaling a hand-off can be made to the
%   common code. The code here is split into two as this allows sharing
%   with the auto-resizing functions.
%    \begin{macrocode}
\cs_new_protected:Npn \box_scale:Nnn #1#2#3
  { \@@_scale:NnnN #1 {#2} {#3} \hbox_set:Nn }
\cs_generate_variant:Nn \box_scale:Nnn { c }
\cs_new_protected:Npn \box_gscale:Nnn #1#2#3
  { \@@_scale:NnnN #1 {#2} {#3} \hbox_gset:Nn }
\cs_generate_variant:Nn \box_gscale:Nnn { c }
\cs_new_protected:Npn \@@_scale:NnnN #1#2#3#4
  {
    #4 #1
      {
        \fp_set:Nn \l_@@_scale_x_fp {#2}
        \fp_set:Nn \l_@@_scale_y_fp {#3}
        \@@_scale:N #1
      }
  }
\cs_new_protected:Npn \@@_scale:N #1
  {
    \dim_set:Nn \l_@@_top_dim    {  \box_ht:N #1 }
    \dim_set:Nn \l_@@_bottom_dim { -\box_dp:N #1 }
    \dim_set:Nn \l_@@_right_dim  {  \box_wd:N #1 }
    \dim_zero:N \l_@@_left_dim
    \dim_set:Nn \l_@@_top_new_dim
      { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_top_dim }
    \dim_set:Nn \l_@@_bottom_new_dim
      { \fp_abs:n { \l_@@_scale_y_fp } \l_@@_bottom_dim }
    \dim_set:Nn \l_@@_right_new_dim
      { \fp_abs:n { \l_@@_scale_x_fp } \l_@@_right_dim }
    \@@_resize_common:N #1
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_autosize_to_wd_and_ht:Nnn          ,
%     \box_autosize_to_wd_and_ht:cnn          ,
%     \box_gautosize_to_wd_and_ht:Nnn         ,
%     \box_gautosize_to_wd_and_ht:cnn         ,
%     \box_autosize_to_wd_and_ht_plus_dp:Nnn  ,
%     \box_autosize_to_wd_and_ht_plus_dp:cnn  ,
%     \box_gautosize_to_wd_and_ht_plus_dp:Nnn ,
%     \box_gautosize_to_wd_and_ht_plus_dp:cnn
%   }
% \begin{macro}{\@@_autosize:NnnnN}
%   Although autosizing a box uses dimensions, it has more in common in
%   implementation with scaling. As such, most of the real work here is
%   done elsewhere.
%    \begin{macrocode}
\cs_new_protected:Npn \box_autosize_to_wd_and_ht:Nnn #1#2#3
  { \@@_autosize:NnnnN #1 {#2} {#3} { \box_ht:N #1 } \hbox_set:Nn }
\cs_generate_variant:Nn \box_autosize_to_wd_and_ht:Nnn { c }
\cs_new_protected:Npn \box_gautosize_to_wd_and_ht:Nnn #1#2#3
  { \@@_autosize:NnnnN #1 {#2} {#3} { \box_ht:N #1 } \hbox_gset:Nn }
\cs_generate_variant:Nn \box_gautosize_to_wd_and_ht:Nnn { c }
\cs_new_protected:Npn \box_autosize_to_wd_and_ht_plus_dp:Nnn #1#2#3
  {
    \@@_autosize:NnnnN #1 {#2} {#3} { \box_ht:N #1 + \box_dp:N #1 }
      \hbox_set:Nn
  }
\cs_generate_variant:Nn \box_autosize_to_wd_and_ht_plus_dp:Nnn { c }
\cs_new_protected:Npn \box_gautosize_to_wd_and_ht_plus_dp:Nnn #1#2#3
  {
    \@@_autosize:NnnnN #1 {#2} {#3} { \box_ht:N #1 + \box_dp:N #1 }
      \hbox_gset:Nn
  }
\cs_generate_variant:Nn \box_gautosize_to_wd_and_ht_plus_dp:Nnn { c }
\cs_new_protected:Npn \@@_autosize:NnnnN #1#2#3#4#5
  {
    #5 #1
      {
        \fp_set:Nn \l_@@_scale_x_fp { ( \dim_to_fp:n {#2} ) / \box_wd:N #1 }
        \fp_set:Nn \l_@@_scale_y_fp
          { (  \dim_to_fp:n {#3} ) / ( \dim_to_fp:n {#4} ) }
        \fp_compare:nNnTF \l_@@_scale_x_fp > \l_@@_scale_y_fp
          { \fp_set_eq:NN \l_@@_scale_x_fp \l_@@_scale_y_fp }
          { \fp_set_eq:NN \l_@@_scale_y_fp \l_@@_scale_x_fp }
        \@@_scale:N #1
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\@@_resize_common:N}
%   The main resize function places its input into a box which start
%   off with zero width, and includes the handles for engine rescaling.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_resize_common:N #1
  {
    \hbox_set:Nn \l_@@_tmp_box
      {
        \@@_backend_scale:Nnn
          #1
          \l_@@_scale_x_fp
          \l_@@_scale_y_fp
      }
%    \end{macrocode}
%   The new height and depth can be applied directly.
%    \begin{macrocode}
    \fp_compare:nNnTF \l_@@_scale_y_fp > \c_zero_fp
      {
        \box_set_ht:Nn \l_@@_tmp_box { \l_@@_top_new_dim }
        \box_set_dp:Nn \l_@@_tmp_box { -\l_@@_bottom_new_dim }
      }
      {
        \box_set_dp:Nn \l_@@_tmp_box { \l_@@_top_new_dim }
        \box_set_ht:Nn \l_@@_tmp_box { -\l_@@_bottom_new_dim }
      }
%    \end{macrocode}
%   Things are not quite as obvious for the width, as the reference point
%   needs to remain unchanged. For positive scaling factors resizing the
%   box is all that is needed. However, for case of a negative scaling
%   the material must be shifted such that the reference point ends up in
%   the right place.
%    \begin{macrocode}
    \fp_compare:nNnTF \l_@@_scale_x_fp < \c_zero_fp
      {
        \hbox_to_wd:nn { \l_@@_right_new_dim }
          {
            \dim_horizontal:N \l_@@_right_new_dim
            \box_use_drop:N \l_@@_tmp_box
            \tex_hss:D
          }
      }
      {
        \box_set_wd:Nn \l_@@_tmp_box { \l_@@_right_new_dim }
        \hbox:n
          {
            \dim_horizontal:n{ 0pt }
            \box_use_drop:N \l_@@_tmp_box
            \tex_hss:D
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \subsection{Adding frames to boxes}
%
% \begin{macro}{\@@_rule_horizontal:nn}
% \begin{macro}{\@@_rule_vertical:n}
%   Wrappers around the \TeX{} primitives for creating rules, with the usual
%   dimension expression support. The non-expanding rule is set up in
%   horizontal mode as that is usually the best plan. The \cs{scan_stop:}
%   is needed here as \TeX{} continues to scan for keywords: multiple uses
%   of the same word are permitted. (Thanks to Ruixi Zhang for pointing this
%   out.) At some stage these will presumably move to a different (public)
%   place.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_rule_horizontal:nn #1#2
  {
    \tex_hrule:D
      height \@@_dim_eval:n {#1}
      depth  \@@_dim_eval:n {#2}
      \scan_stop:
  }
\cs_new_protected:Npn \@@_rule_vertical:n #1
  { \tex_vrule:D width \@@_dim_eval:n {#1} \scan_stop: }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_frame:Nnn, \box_frame:cnn,
%     \box_gframe:Nnn, \box_gframe:cnn,
%   }
% \begin{macro}{\@@_frame:nnNN, \@@_frame:eeNN}
%   Framing a box requires the depth is known, so there has to be an
%   assignment step first to allow this measurement. The actual
%   insertion is done such that the content goes in \enquote{behind}
%   the rules. That requires a bit of shuffling so that the final box is the
%   correct size, including the necessary border, while keeping the reference
%   point in the right place.
%    \begin{macrocode}
\cs_new_protected:Npn \box_frame:Nnn #1#2#3
  {
    \@@_frame:eeNN { \dim_eval:n {#2} } { \dim_eval:n {#3} }
      #1 \hbox_set:Nn
  }
\cs_generate_variant:Nn \box_frame:Nnn { c }
\cs_new_protected:Npn \box_gframe:Nnn #1#2#3
  {
    \@@_frame:eeNN { \dim_eval:n {#2} } { \dim_eval:n {#3} }
      #1 \hbox_gset:Nn
  }
\cs_generate_variant:Nn \box_gframe:Nnn { c }
\cs_new_protected:Npn \@@_frame:nnNN #1#2#3#4
  {
    #4 #3
      {
        \dim_horizontal:n { #1 + #2 }
        \box_use:N #3
        \dim_horizontal:n { -\box_wd:N #3 - #1 - #2 }
        \box_move_down:nn { \box_dp:N #3 + #1 + #2 }
          {
            \vbox:n
              {
                \@@_rule_horizontal:nn {#2} { \c_zero_dim }
                \hbox:n
                  {
                    \@@_rule_vertical:n {#2}
                    \dim_horizontal:n { #1 * 2 + \box_wd:N #3 }
                    \vbox:n
                      {
                        \dim_vertical:n
                          { #1 * 2 + \box_dp:N #3 + \box_ht:N #3 }
                      }
                     \@@_rule_vertical:n {#2}
                  }
                \@@_rule_horizontal:nn {#2} { \c_zero_dim }
              }
          }
      }
  }
\cs_generate_variant:Nn \@@_frame:nnNN { ee }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_underline:Nnn, \box_underline:cnn,
%     \box_gunderline:Nnn, \box_gunderline:cnn
%   }
% \begin{macro}{\@@_underline:nnNN, \@@_underline:eeNN}
%   A cut-down version of framing, with just one side marked.
%    \begin{macrocode}
\cs_new_protected:Npn \box_underline:Nnn #1#2#3
  {
    \@@_underline:eeNN
      { \dim_eval:n {#2} } { \dim_eval:n {#3} }
      #1 \hbox_set:Nn
  }
\cs_generate_variant:Nn \box_underline:Nnn { c }
\cs_new_protected:Npn \box_gunderline:Nnn #1#2#3
  {
    \@@_underline:eeNN
      { \dim_eval:n {#2} } { \dim_eval:n {#3} }
      #1 \hbox_gset:Nn
  }
\cs_generate_variant:Nn \box_gunderline:Nnn { c }
\cs_new_protected:Npn \@@_underline:nnNN #1#2#3#4
  {
    #4 #3
      {
        \box_use:N #3
        \dim_horizontal:n { -\box_wd:N #3 }
        \box_move_down:nn { \box_dp:N #3 + #1 + #2 }
          {
            \vbox:n
              {
                \hbox:n { \dim_horizontal:n { \box_wd:N #3 } }
                \@@_rule_horizontal:nn {#2} { \c_zero_dim }
              }
          }
      }
  }
\cs_generate_variant:Nn \@@_underline:nnNN { ee }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \subsection{Viewing part of a box}
%
% \begin{macro}{\box_set_clipped:N, \box_set_clipped:c, \box_gset_clipped:N, \box_gset_clipped:c}
%   A wrapper around the driver-dependent code.
%    \begin{macrocode}
\cs_new_protected:Npn \box_set_clipped:N #1
  { \hbox_set:Nn #1 { \@@_backend_clip:N #1 } }
\cs_generate_variant:Nn \box_set_clipped:N { c }
\cs_new_protected:Npn \box_gset_clipped:N #1
  { \hbox_gset:Nn #1 { \@@_backend_clip:N #1 } }
\cs_generate_variant:Nn \box_gset_clipped:N { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_set_trim:Nnnnn, \box_set_trim:cnnnn,
%     \box_gset_trim:Nnnnn, \box_gset_trim:cnnnn
%   }
% \begin{macro}{\@@_set_trim:NnnnnN}
%   Trimming from the left- and right-hand edges of the box is easy: kern the
%   appropriate parts off each side.
%    \begin{macrocode}
\cs_new_protected:Npn \box_set_trim:Nnnnn #1#2#3#4#5
  { \@@_set_trim:NnnnnN #1 {#2} {#3} {#4} {#5} \box_set_eq:NN }
\cs_generate_variant:Nn \box_set_trim:Nnnnn { c }
\cs_new_protected:Npn \box_gset_trim:Nnnnn #1#2#3#4#5
  { \@@_set_trim:NnnnnN #1 {#2} {#3} {#4} {#5} \box_gset_eq:NN }
\cs_generate_variant:Nn \box_gset_trim:Nnnnn { c }
\cs_new_protected:Npn \@@_set_trim:NnnnnN #1#2#3#4#5#6
  {
    \hbox_set:Nn \l_@@_tmp_box
      {
        \dim_horizontal:n { -#2 }
        \box_use:N #1
        \dim_horizontal:n { -#4 }
      }
%    \end{macrocode}
%   For the height and depth, there is a need to watch the baseline is
%   respected. Material always has to stay on the correct side, so trimming
%   has to check that there is enough material to trim. First, the bottom
%   edge. If there is enough depth, simply set the depth, or if not move
%   down so the result is zero depth. \cs{box_move_down:nn} is used in both
%   cases so the resulting box always contains a \tn{lower} primitive.
%   The internal box is used here as it allows safe use of \cs{box_set_dp:Nn}.
%    \begin{macrocode}
    \dim_compare:nNnTF { \box_dp:N #1 } > {#3}
      {
        \hbox_set:Nn \l_@@_tmp_box
          {
            \box_move_down:nn \c_zero_dim
              { \box_use_drop:N \l_@@_tmp_box }
          }
        \box_set_dp:Nn \l_@@_tmp_box { \box_dp:N #1 - (#3) }
      }
      {
        \hbox_set:Nn \l_@@_tmp_box
          {
            \box_move_down:nn { (#3) - \box_dp:N #1 }
              { \box_use_drop:N \l_@@_tmp_box }
          }
        \box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
      }
%    \end{macrocode}
%   Same thing, this time from the top of the box.
%    \begin{macrocode}
    \dim_compare:nNnTF { \box_ht:N \l_@@_tmp_box } > {#5}
      {
        \hbox_set:Nn \l_@@_tmp_box
          {
            \box_move_up:nn \c_zero_dim
              { \box_use_drop:N \l_@@_tmp_box }
          }
        \box_set_ht:Nn \l_@@_tmp_box
          { \box_ht:N \l_@@_tmp_box - (#5) }
      }
      {
        \hbox_set:Nn \l_@@_tmp_box
          {
            \box_move_up:nn { (#5) - \box_ht:N \l_@@_tmp_box }
              { \box_use_drop:N \l_@@_tmp_box }
          }
        \box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
      }
    #6 #1 \l_@@_tmp_box
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}
%   {
%     \box_set_viewport:Nnnnn, \box_set_viewport:cnnnn,
%     \box_gset_viewport:Nnnnn, \box_gset_viewport:cnnnn
%   }
% \begin{macro}{\@@_viewport:NnnnnN}
%   The same general logic as for the trim operation, but with absolute
%   dimensions. As a result, there are some things to watch out for in the
%   vertical direction.
%    \begin{macrocode}
\cs_new_protected:Npn \box_set_viewport:Nnnnn #1#2#3#4#5
  { \@@_set_viewport:NnnnnN #1 {#2} {#3} {#4} {#5} \box_set_eq:NN }
\cs_generate_variant:Nn \box_set_viewport:Nnnnn { c }
\cs_new_protected:Npn \box_gset_viewport:Nnnnn #1#2#3#4#5
  { \@@_set_viewport:NnnnnN #1 {#2} {#3} {#4} {#5} \box_gset_eq:NN }
\cs_generate_variant:Nn \box_gset_viewport:Nnnnn { c }
\cs_new_protected:Npn \@@_set_viewport:NnnnnN #1#2#3#4#5#6
  {
    \hbox_set:Nn \l_@@_tmp_box
      {
        \dim_horizontal:n { -#2 }
        \box_use:N #1
        \dim_horizontal:n { #4 - \box_wd:N #1 }
      }
    \dim_compare:nNnTF {#3} < \c_zero_dim
      {
        \hbox_set:Nn \l_@@_tmp_box
          {
            \box_move_down:nn \c_zero_dim
              { \box_use_drop:N \l_@@_tmp_box }
          }
        \box_set_dp:Nn \l_@@_tmp_box { - \@@_dim_eval:n {#3} }
      }
      {
        \hbox_set:Nn \l_@@_tmp_box
          { \box_move_down:nn {#3} { \box_use_drop:N \l_@@_tmp_box } }
        \box_set_dp:Nn \l_@@_tmp_box \c_zero_dim
      }
    \dim_compare:nNnTF {#5} > \c_zero_dim
      {
        \hbox_set:Nn \l_@@_tmp_box
          {
            \box_move_up:nn \c_zero_dim
              { \box_use_drop:N \l_@@_tmp_box }
          }
        \box_set_ht:Nn \l_@@_tmp_box
          {
            (#5)
            \dim_compare:nNnT {#3} > \c_zero_dim
              { - (#3) }
          }
      }
      {
        \hbox_set:Nn \l_@@_tmp_box
          {
            \box_move_up:nn { - \@@_dim_eval:n {#5} }
              { \box_use_drop:N \l_@@_tmp_box }
          }
        \box_set_ht:Nn \l_@@_tmp_box \c_zero_dim
      }
    #6 #1 \l_@@_tmp_box
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%</code>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex
