diff options
Diffstat (limited to 'Master/texmf-dist/source/latex/l3kernel/l3box.dtx')
-rw-r--r-- | Master/texmf-dist/source/latex/l3kernel/l3box.dtx | 815 |
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} |