summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3box.dtx')
-rw-r--r--Master/texmf-dist/source/latex/l3kernel/l3box.dtx815
1 files changed, 775 insertions, 40 deletions
diff --git a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
index edbf6b7b652..b7ac16ab656 100644
--- a/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
+++ b/Master/texmf-dist/source/latex/l3kernel/l3box.dtx
@@ -41,7 +41,7 @@
% }^^A
% }
%
-% \date{Released 2017/04/01}
+% \date{Released 2017/05/13}
%
% \maketitle
%
@@ -335,9 +335,14 @@
% group levels.
% \end{function}
%
+% \section{Boxes and color}
+%
+% All \LaTeX{}3 boxes are \enquote{color safe}: a color set inside the box
+% will not apply after the end of the box has occurred.
+%
% \section{Horizontal mode boxes}
%
-% \begin{function}{\hbox:n}
+% \begin{function}[updated = 2017-04-05]{\hbox:n}
% \begin{syntax}
% \cs{hbox:n} \Arg{contents}
% \end{syntax}
@@ -345,7 +350,7 @@
% width and then includes this box in the current list for typesetting.
% \end{function}
%
-% \begin{function}{\hbox_to_wd:nn}
+% \begin{function}[updated = 2017-04-05]{\hbox_to_wd:nn}
% \begin{syntax}
% \cs{hbox_to_wd:nn} \Arg{dimexpr} \Arg{contents}
% \end{syntax}
@@ -354,7 +359,7 @@
% typesetting.
% \end{function}
%
-% \begin{function}{\hbox_to_zero:n}
+% \begin{function}[updated = 2017-04-05]{\hbox_to_zero:n}
% \begin{syntax}
% \cs{hbox_to_zero:n} \Arg{contents}
% \end{syntax}
@@ -362,7 +367,8 @@
% and then includes this box in the current list for typesetting.
% \end{function}
%
-% \begin{function}{\hbox_set:Nn, \hbox_set:cn, \hbox_gset:Nn, \hbox_gset:cn}
+% \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}
@@ -370,7 +376,7 @@
% result inside the \meta{box}.
% \end{function}
%
-% \begin{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
@@ -382,7 +388,7 @@
% and then stores the result inside the \meta{box}.
% \end{function}
%
-% \begin{function}{\hbox_overlap_right:n}
+% \begin{function}[updated = 2017-04-05]{\hbox_overlap_right:n}
% \begin{syntax}
% \cs{hbox_overlap_right:n} \Arg{contents}
% \end{syntax}
@@ -391,7 +397,7 @@
% point.
% \end{function}
%
-% \begin{function}{\hbox_overlap_left:n}
+% \begin{function}[updated = 2017-04-05]{\hbox_overlap_left:n}
% \begin{syntax}
% \cs{hbox_overlap_left:n} \Arg{contents}
% \end{syntax}
@@ -400,7 +406,7 @@
% point.
% \end{function}
%
-% \begin{function}
+% \begin{function}[updated = 2017-04-05]
% {
% \hbox_set:Nw, \hbox_set:cw,
% \hbox_set_end:,
@@ -451,18 +457,15 @@
% is that of the first item added. These tend to have a large depth and
% small height, although the latter will typically be non-zero.
%
-% \begin{function}[updated = 2011-12-18]{\vbox:n}
+% \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.
-% \begin{texnote}
-% This is the \TeX{} primitive \tn{vbox}.
-% \end{texnote}
% \end{function}
%
-% \begin{function}[updated = 2011-12-18]{\vbox_top:n}
+% \begin{function}[updated = 2017-04-05]{\vbox_top:n}
% \begin{syntax}
% \cs{vbox_top:n} \Arg{contents}
% \end{syntax}
@@ -470,12 +473,9 @@
% and includes this box in the current list for typesetting. The
% baseline of the box will be equal to that of the \emph{first}
% item added to the box.
-% \begin{texnote}
-% This is the \TeX{} primitive \tn{vtop}.
-% \end{texnote}
% \end{function}
%
-% \begin{function}[updated = 2011-12-18]{\vbox_to_ht:nn}
+% \begin{function}[updated = 2017-04-05]{\vbox_to_ht:nn}
% \begin{syntax}
% \cs{vbox_to_ht:nn} \Arg{dimexpr} \Arg{contents}
% \end{syntax}
@@ -484,7 +484,7 @@
% typesetting.
% \end{function}
%
-% \begin{function}[updated = 2011-12-18]{\vbox_to_zero:n}
+% \begin{function}[updated = 2017-04-05]{\vbox_to_zero:n}
% \begin{syntax}
% \cs{vbox_to_zero:n} \Arg{contents}
% \end{syntax}
@@ -492,7 +492,7 @@
% and then includes this box in the current list for typesetting.
% \end{function}
%
-% \begin{function}[updated = 2011-12-18]
+% \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}
@@ -501,7 +501,7 @@
% result inside the \meta{box}.
% \end{function}
%
-% \begin{function}[updated = 2011-12-18]
+% \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}
@@ -511,7 +511,7 @@
% to that of the \emph{first} item added to the box.
% \end{function}
%
-% \begin{function}[updated = 2011-12-18]
+% \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
@@ -523,7 +523,7 @@
% \meta{dimexpr} and then stores the result inside the \meta{box}.
% \end{function}
%
-% \begin{function}[updated = 2011-12-18]
+% \begin{function}[updated = 2017-04-058]
% {
% \vbox_set:Nw, \vbox_set:cw,
% \vbox_set_end:,
@@ -575,6 +575,162 @@
% \end{texnote}
% \end{function}
%
+% \subsection{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]
+% {\box_autosize_to_wd_and_ht:Nnn, \box_autosize_to_wd_and_ht:Nnn}
+% \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} will be an |hbox|, irrespective of the nature
+% of the \meta{box} before the resizing is applied. The final size of the
+% \meta{box} will be the smaller of \Arg{x-size} and \Arg{y-size},
+% \emph{i.e.}~the result will fit within the dimensions specified. Negative
+% sizes will cause the material in the \meta{box} to be reversed in direction,
+% but the reference point of the \meta{box} will be unchanged. Thus a negative
+% \meta{y-size} will result in the \meta{box} having a depth dependent on the
+% height of the original and \emph{vice versa}. The resizing applies within
+% the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}[added = 2017-04-04]
+% {\box_autosize_to_wd_and_ht_plus_dp:Nnn, \box_autosize_to_wd_and_ht_plus_dp:Nnn}
+% \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} will be an |hbox|, irrespective of the nature
+% of the \meta{box} before the resizing is applied. The final size of the
+% \meta{box} will be the smaller of \Arg{x-size} and \Arg{y-size},
+% \emph{i.e.}~the result will fit within the dimensions specified. Negative
+% sizes will cause the material in the \meta{box} to be reversed in direction,
+% but the reference point of the \meta{box} will be unchanged. Thus a negative
+% \meta{y-size} will result in the \meta{box} having a depth dependent on the
+% height of the original and \emph{vice versa}. The resizing applies within
+% the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}
+% {\box_resize_to_ht:Nn, \box_resize_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} will be an |hbox|, irrespective of the nature of the \meta{box}
+% before the resizing is applied. A negative \meta{y-size} will cause the
+% material in the \meta{box} to be reversed in direction, but the reference
+% point of the \meta{box} will be unchanged. Thus a negative \meta{y-size}
+% will result in the \meta{box} having a depth dependent on the height of the
+% original and \emph{vice versa}. The resizing applies within the current
+% \TeX{} group level.
+% \end{function}
+%
+% \begin{function}
+% {\box_resize_to_ht_plus_dp:Nn, \box_resize_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} will be an |hbox|, irrespective of the nature of the \meta{box}
+% before the resizing is applied. A negative \meta{y-size} will cause
+% the material in the \meta{box} to be reversed in direction, but the
+% reference point of the \meta{box} will be unchanged. Thus a negative
+% \meta{y-size} will result in the \meta{box} having a depth dependent on the
+% height of the original and \emph{vice versa}. The resizing applies within
+% the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}{\box_resize_to_wd:Nn, \box_resize_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} will be an |hbox|, irrespective of the nature of the \meta{box}
+% before the resizing is applied. A negative \meta{x-size} will cause the
+% material in the \meta{box} to be reversed in direction, but the reference
+% point of the \meta{box} will be unchanged. Thus a negative \meta{x-size}
+% will result in the \meta{box} having a depth dependent on the height of the
+% original and \emph{vice versa}. The resizing applies within the current
+% \TeX{} group level.
+% \end{function}
+%
+% \begin{function}[added = 2014-07-03]
+% {\box_resize_to_wd_and_ht:Nnn, \box_resize_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} will be an |hbox|, irrespective of the nature of the \meta{box}
+% before the resizing is applied. Negative sizes will cause the material in
+% the \meta{box} to be reversed in direction, but the reference point of the
+% \meta{box} will be unchanged. Thus a negative \meta{y-size} will result in
+% the \meta{box} having a depth dependent on the height of the original and
+% \emph{vice versa}. The resizing applies within the current \TeX{} group
+% level.
+% \end{function}
+%
+% \begin{function}[added = 2017-04-06]
+% {\box_resize_to_wd_and_ht_plus_dp:Nnn, \box_resize_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} will be an |hbox|, irrespective of the nature of the \meta{box}
+% before the resizing is applied. Negative sizes will cause the material in
+% the \meta{box} to be reversed in direction, but the reference point of the
+% \meta{box} will be unchanged. Thus a negative \meta{y-size} will result in
+% the \meta{box} having a depth dependent on the height of the original and
+% \emph{vice versa}. The resizing applies within the current \TeX{} group
+% level.
+% \end{function}
+%
+% \begin{function}{\box_rotate:Nn, \box_rotate:cn}
+% \begin{syntax}
+% \cs{box_rotate:Nn} \meta{box} \Arg{angle}
+% \end{syntax}
+% Rotates the \meta{box} by \meta{angle} (in degrees) anti-clockwise about
+% its reference point. The reference point of the updated box will be moved
+% horizontally such that it is at the left side of the smallest rectangle
+% enclosing the rotated material. The updated \meta{box} will be an |hbox|,
+% irrespective of the nature of the \meta{box} before the rotation is applied.
+% The rotation applies within the current \TeX{} group level.
+% \end{function}
+%
+% \begin{function}{\box_scale:Nnn, \box_scale: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
+% integer expressions). The updated \meta{box} will be an |hbox|, irrespective
+% of the nature of the \meta{box} before the scaling is applied. Negative
+% scalings will cause the material in the \meta{box} to be reversed in
+% direction, but the reference point of the \meta{box} will be unchanged.
+% Thus a negative \meta{y-scale} will result in the \meta{box} having a depth
+% dependent on the height of the original and \emph{vice versa}. The resizing
+% applies within the current \TeX{} group level.
+% \end{function}
+%
% \section{Primitive box conditionals}
%
% \begin{function}[EXP]{\if_hbox:N}
@@ -976,7 +1132,8 @@
% \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: {#1} }
+\cs_new_protected:Npn \hbox:n #1
+ { \tex_hbox:D \scan_stop: { \group_begin: #1 \group_end: } }
% \end{macrocode}
% \end{macro}
%
@@ -985,7 +1142,7 @@
% \testfile*
% \begin{macrocode}
\cs_new_protected:Npn \hbox_set:Nn #1#2
- { \tex_setbox:D #1 \tex_hbox:D {#2} }
+ { \tex_setbox:D #1 \tex_hbox:D { \group_begin: #2 \group_end: } }
\cs_new_protected:Npn \hbox_gset:Nn { \tex_global:D \hbox_set:Nn }
\cs_generate_variant:Nn \hbox_set:Nn { c }
\cs_generate_variant:Nn \hbox_gset:Nn { c }
@@ -999,7 +1156,10 @@
% Storing material in a horizontal box with a specified width.
% \begin{macrocode}
\cs_new_protected:Npn \hbox_set_to_wd:Nnn #1#2#3
- { \tex_setbox:D #1 \tex_hbox:D to \__dim_eval:w #2 \__dim_eval_end: {#3} }
+ {
+ \tex_setbox:D #1 \tex_hbox:D to \__dim_eval:w #2 \__dim_eval_end:
+ { \group_begin: #3 \group_end: }
+ }
\cs_new_protected:Npn \hbox_gset_to_wd:Nnn
{ \tex_global:D \hbox_set_to_wd:Nnn }
\cs_generate_variant:Nn \hbox_set_to_wd:Nnn { c }
@@ -1016,13 +1176,21 @@
% environment definitions.
% \begin{macrocode}
\cs_new_protected:Npn \hbox_set:Nw #1
- { \tex_setbox:D #1 \tex_hbox:D \c_group_begin_token }
+ {
+ \tex_setbox:D #1 \tex_hbox:D
+ \c_group_begin_token
+ \group_begin:
+ }
\cs_new_protected:Npn \hbox_gset:Nw
{ \tex_global:D \hbox_set:Nw }
\cs_generate_variant:Nn \hbox_set:Nw { c }
\cs_generate_variant:Nn \hbox_gset:Nw { c }
-\cs_new_eq:NN \hbox_set_end: \c_group_end_token
-\cs_new_eq:NN \hbox_gset_end: \c_group_end_token
+\cs_new_protected:Npn \hbox_set_end:
+ {
+ \group_end:
+ \c_group_end_token
+ }
+\cs_new_eq:NN \hbox_gset_end: \hbox_set_end:
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1034,8 +1202,12 @@
% 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:w #1 \__dim_eval_end: {#2} }
-\cs_new_protected:Npn \hbox_to_zero:n #1 { \tex_hbox:D to \c_zero_dim {#1} }
+ {
+ \tex_hbox:D to \__dim_eval:w #1 \__dim_eval_end:
+ { \group_begin: #2 \group_end: }
+ }
+\cs_new_protected:Npn \hbox_to_zero:n #1
+ { \tex_hbox:D to \c_zero_dim { \group_begin: #1 \group_end: } }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1076,8 +1248,10 @@
% \TestFiles{m3box003.lvt}
% Put a vertical box directly into the input stream.
% \begin{macrocode}
-\cs_new_protected:Npn \vbox:n #1 { \tex_vbox:D { #1 \par } }
-\cs_new_protected:Npn \vbox_top:n #1 { \tex_vtop:D { #1 \par } }
+\cs_new_protected:Npn \vbox:n #1
+ { \tex_vbox:D { \group_begin: #1 \par \group_end: } }
+\cs_new_protected:Npn \vbox_top:n #1
+ { \tex_vtop:D { \group_begin: #1 \par \group_end: } }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1088,9 +1262,15 @@
% Put a vertical box directly into the input stream.
% \begin{macrocode}
\cs_new_protected:Npn \vbox_to_ht:nn #1#2
- { \tex_vbox:D to \__dim_eval:w #1 \__dim_eval_end: { #2 \par } }
+ {
+ \tex_vbox:D to \__dim_eval:w #1 \__dim_eval_end:
+ { \group_begin: #2 \par \group_end: }
+ }
\cs_new_protected:Npn \vbox_to_zero:n #1
- { \tex_vbox:D to \c_zero_dim { #1 \par } }
+ {
+ \tex_vbox:D to \c_zero_dim
+ { \group_begin: #1 \par \group_end: }
+ }
% \end{macrocode}
% \end{macro}
% \end{macro}
@@ -1101,7 +1281,10 @@
% 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 { #2 \par } }
+ {
+ \tex_setbox:D #1 \tex_vbox:D
+ { \group_begin: #2 \par \group_end: }
+ }
\cs_new_protected:Npn \vbox_gset:Nn { \tex_global:D \vbox_set:Nn }
\cs_generate_variant:Nn \vbox_set:Nn { c }
\cs_generate_variant:Nn \vbox_gset:Nn { c }
@@ -1116,7 +1299,10 @@
% 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 { #2 \par } }
+ {
+ \tex_setbox:D #1 \tex_vtop:D
+ { \group_begin: #2 \par \group_end: }
+ }
\cs_new_protected:Npn \vbox_gset_top:Nn
{ \tex_global:D \vbox_set_top:Nn }
\cs_generate_variant:Nn \vbox_set_top:Nn { c }
@@ -1133,7 +1319,7 @@
\cs_new_protected:Npn \vbox_set_to_ht:Nnn #1#2#3
{
\tex_setbox:D #1 \tex_vbox:D to \__dim_eval:w #2 \__dim_eval_end:
- { #3 \par }
+ { \group_begin: #3 \par \group_end: }
}
\cs_new_protected:Npn \vbox_gset_to_ht:Nnn
{ \tex_global:D \vbox_set_to_ht:Nnn }
@@ -1151,14 +1337,19 @@
% environment definitions.
% \begin{macrocode}
\cs_new_protected:Npn \vbox_set:Nw #1
- { \tex_setbox:D #1 \tex_vbox:D \c_group_begin_token }
+ {
+ \tex_setbox:D #1 \tex_vbox:D
+ \c_group_begin_token
+ \group_begin:
+ }
\cs_new_protected:Npn \vbox_gset:Nw
{ \tex_global:D \vbox_set:Nw }
\cs_generate_variant:Nn \vbox_set:Nw { c }
\cs_generate_variant:Nn \vbox_gset:Nw { c }
\cs_new_protected:Npn \vbox_set_end:
{
- \par
+ \par
+ \group_end:
\c_group_end_token
}
\cs_new_eq:NN \vbox_gset_end: \vbox_set_end:
@@ -1189,6 +1380,550 @@
% \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_@@_internal_box}
+% Scratch space, but also needed by some parts of the driver.
+% \begin{macrocode}
+\box_new:N \l_@@_internal_box
+% \end{macrocode}
+% \end{variable}
+%
+% \begin{macro}{\box_rotate:Nn}
+% \begin{macro}[aux]{\@@_rotate:N}
+% \begin{macro}[aux]{\@@_rotate_x:nnN, \@@_rotate_y:nnN}
+% \begin{macro}[aux]
+% {
+% \@@_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
+ {
+ \hbox_set:Nn #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 will
+% always be 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:l3candidates:rotation}). The vertex $O$ is the reference point
+% on the baseline, and in this implementation is also the centre 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{Co-ordinates of a box prior to rotation.}
+% \label{fig:l3candidates: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 will be in the same place as the original.
+% \begin{macrocode}
+ \hbox_set:Nn \l_@@_internal_box { \box_use:N #1 }
+ \hbox_set:Nn \l_@@_internal_box
+ {
+ \tex_kern:D -\l_@@_left_new_dim
+ \hbox:n
+ {
+ \__driver_box_use_rotate:Nn
+ \l_@@_internal_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_@@_internal_box { \l_@@_top_new_dim }
+ \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
+ \box_set_wd:Nn \l_@@_internal_box
+ { \l_@@_right_new_dim - \l_@@_left_new_dim }
+ \box_use:N \l_@@_internal_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_x: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_y: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_y:nnN \l_@@_right_dim \l_@@_top_dim
+ \l_@@_top_new_dim
+ \@@_rotate_y:nnN \l_@@_left_dim \l_@@_bottom_dim
+ \l_@@_bottom_new_dim
+ \@@_rotate_x:nnN \l_@@_left_dim \l_@@_top_dim
+ \l_@@_left_new_dim
+ \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim
+ \l_@@_right_new_dim
+ }
+\cs_new_protected:Npn \@@_rotate_quadrant_two:
+ {
+ \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim
+ \l_@@_top_new_dim
+ \@@_rotate_y:nnN \l_@@_left_dim \l_@@_top_dim
+ \l_@@_bottom_new_dim
+ \@@_rotate_x:nnN \l_@@_right_dim \l_@@_top_dim
+ \l_@@_left_new_dim
+ \@@_rotate_x:nnN \l_@@_left_dim \l_@@_bottom_dim
+ \l_@@_right_new_dim
+ }
+\cs_new_protected:Npn \@@_rotate_quadrant_three:
+ {
+ \@@_rotate_y:nnN \l_@@_left_dim \l_@@_bottom_dim
+ \l_@@_top_new_dim
+ \@@_rotate_y:nnN \l_@@_right_dim \l_@@_top_dim
+ \l_@@_bottom_new_dim
+ \@@_rotate_x:nnN \l_@@_right_dim \l_@@_bottom_dim
+ \l_@@_left_new_dim
+ \@@_rotate_x:nnN \l_@@_left_dim \l_@@_top_dim
+ \l_@@_right_new_dim
+ }
+\cs_new_protected:Npn \@@_rotate_quadrant_four:
+ {
+ \@@_rotate_y:nnN \l_@@_left_dim \l_@@_top_dim
+ \l_@@_top_new_dim
+ \@@_rotate_y:nnN \l_@@_right_dim \l_@@_bottom_dim
+ \l_@@_bottom_new_dim
+ \@@_rotate_x:nnN \l_@@_left_dim \l_@@_bottom_dim
+ \l_@@_left_new_dim
+ \@@_rotate_x:nnN \l_@@_right_dim \l_@@_top_dim
+ \l_@@_right_new_dim
+ }
+% \end{macrocode}
+% \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}
+% \begin{macro}[aux]{\@@_resize_set_corners:N}
+% \begin{macro}[aux]{\@@_resize:N}
+% \begin{macro}[aux]{\@@_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
+ {
+ \hbox_set:Nn #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_generate_variant:Nn \box_resize_to_wd_and_ht_plus_dp:Nnn { c }
+\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 co-ordinates. 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}
+%
+% \begin{macro}{\box_resize_to_ht:Nn, \box_resize_to_ht:cn}
+% \begin{macro}{\box_resize_to_ht_plus_dp:Nn, \box_resize_to_ht_plus_dp:cn}
+% \begin{macro}{\box_resize_to_wd:Nn, \box_resize_to_wd:cn}
+% \begin{macro}{\box_resize_to_wd_and_ht:Nnn, \box_resize_to_wd_and_ht:cnn}
+% 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
+ {
+ \hbox_set:Nn #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_generate_variant:Nn \box_resize_to_ht:Nn { c }
+\cs_new_protected:Npn \box_resize_to_ht_plus_dp:Nn #1#2
+ {
+ \hbox_set:Nn #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_generate_variant:Nn \box_resize_to_ht_plus_dp:Nn { c }
+\cs_new_protected:Npn \box_resize_to_wd:Nn #1#2
+ {
+ \hbox_set:Nn #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_generate_variant:Nn \box_resize_to_wd:Nn { c }
+\cs_new_protected:Npn \box_resize_to_wd_and_ht:Nnn #1#2#3
+ {
+ \hbox_set:Nn #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
+ }
+ }
+\cs_generate_variant:Nn \box_resize_to_wd_and_ht:Nnn { c }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}{\box_scale:Nnn, \box_scale:cnn}
+% \begin{macro}[aux]{\@@_scale_aux: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
+ {
+ \hbox_set:Nn #1
+ {
+ \fp_set:Nn \l_@@_scale_x_fp {#2}
+ \fp_set:Nn \l_@@_scale_y_fp {#3}
+ \@@_scale_aux:N #1
+ }
+ }
+\cs_generate_variant:Nn \box_scale:Nnn { c }
+\cs_new_protected:Npn \@@_scale_aux: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}
+%
+% \begin{macro}
+% {
+% \box_autosize_to_wd_and_ht:Nnn ,
+% \box_autosize_to_wd_and_ht:cnn ,
+% \box_autosize_to_wd_and_ht_plus_dp:cnn ,
+% \box_autosize_to_wd_and_ht_plus_dp:Nnn
+% }
+% \begin{macro}[aux]{\@@_autosize:Nnnn}
+% 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:Nnnn #1 {#2} {#3} { \box_ht:N #1 } }
+\cs_generate_variant:Nn \box_autosize_to_wd_and_ht:Nnn { c }
+\cs_new_protected:Npn \box_autosize_to_wd_and_ht_plus_dp:Nnn #1#2#3
+ { \@@_autosize:Nnnn #1 {#2} {#3} { \box_ht:N #1 + \box_dp:N #1 } }
+\cs_generate_variant:Nn \box_autosize_to_wd_and_ht_plus_dp:Nnn { c }
+\cs_new_protected:Npn \@@_autosize:Nnnn #1#2#3#4
+ {
+ \hbox_set:Nn #1
+ {
+ \fp_set:Nn \l_@@_scale_x_fp { ( #2 ) / \box_wd:N #1 }
+ \fp_set:Nn \l_@@_scale_y_fp { ( #3 ) / ( #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_aux:N #1
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+% \end{macro}
+%
+% \begin{macro}[aux]{\@@_resize_common:N}
+% The main resize function places in input into a box which will start
+% of with zero width, and includes the handles for engine rescaling.
+% \begin{macrocode}
+\cs_new_protected:Npn \@@_resize_common:N #1
+ {
+ \hbox_set:Nn \l_@@_internal_box
+ {
+ \__driver_box_use_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_@@_internal_box { \l_@@_top_new_dim }
+ \box_set_dp:Nn \l_@@_internal_box { -\l_@@_bottom_new_dim }
+ }
+ {
+ \box_set_dp:Nn \l_@@_internal_box { \l_@@_top_new_dim }
+ \box_set_ht:Nn \l_@@_internal_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 }
+ {
+ \tex_kern:D \l_@@_right_new_dim
+ \box_use:N \l_@@_internal_box
+ \tex_hss:D
+ }
+ }
+ {
+ \box_set_wd:Nn \l_@@_internal_box { \l_@@_right_new_dim }
+ \hbox:n
+ {
+ \tex_kern:D \c_zero_dim
+ \box_use:N \l_@@_internal_box
+ \tex_hss:D
+ }
+ }
+ }
+% \end{macrocode}
+% \end{macro}
+%
+% \subsection{Deprecated functions}
+%
+% \begin{macro}{\box_resize:Nnn, \box_resize:cnn}
+% \begin{macrocode}
+\cs_new_eq:NN \box_resize:Nnn \box_resize_to_wd_and_ht_plus_dp:Nnn
+\cs_new_eq:NN \box_resize:cnn \box_resize_to_wd_and_ht_plus_dp:cnn
+% \end{macrocode}
+% \end{macro}
+%
% \begin{macrocode}
%</initex|package>
% \end{macrocode}