% \iffalse meta-comment
% 
%% File: l3coffins.dtx Copyright(C) 2010,2011 The LaTeX3 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
%%
%%    http://www.latex-project.org/lppl.txt
%%
%% This file is part of the "l3experimental bundle" (The Work in LPPL)
%% and all files in that bundle must be distributed together.
%%
%% The released version of this bundle is available from CTAN.
%%
%% -----------------------------------------------------------------------
%%
%% The development version of the bundle can be found at
%%
%%    http://www.latex-project.org/svnroot/experimental/trunk/
%%
%% for those people who are interested.
%%
%%%%%%%%%%%
%% NOTE: %%
%%%%%%%%%%%
%%
%%   Snapshots taken from the repository represent work in progress and may
%%   not work or may contain conflicting material!  We therefore ask
%%   people _not_ to put them into distributions, archives, etc. without
%%   prior consultation with the LaTeX Project Team.
%%
%% -----------------------------------------------------------------------
%%
%
%<*driver|package>
\RequirePackage{expl3}
\GetIdInfo$Id: l3coffins-scaling.dtx 2678 2011-08-28 07:02:32Z joseph $
  {L3 Experimental coffin scaling code}
%</driver|package>
%<*driver>
\documentclass[full]{l3doc}
\begin{document}
  \DocInput{\jobname.dtx}
\end{document}
%</driver>
% \fi
% 
% \title{^^A
%   The \textsf{l3coffins-scaling} package\\ Scaling coffins^^A
%   \thanks{This file describes v\ExplFileVersion,
%     last revised \ExplFileDate.}^^A
% }
%         
% \author{^^A
%  The \LaTeX3 Project\thanks
%    {^^A
%      E-mail:
%        \href{mailto:latex-team@latex-project.org}
%          {latex-team@latex-project.org}^^A
%    }^^A
% }
%
% \date{Released \ExplFileDate}
%
% \maketitle
%
% \begin{documentation}
% 
% The material in this module provides low-level support for scaling
% and resizing coffins. The core coffin implementation is found in
% \pkg{l3coffins} in the \pkg{l3kernel} bundle. In contrast to that stable
% code, this code is highly experimental.
%
% \begin{function}{\coffin_resize:Nnn, \coffin_resize:cnn}
%   \begin{syntax}
%     \cs{coffin_resize:Nnn} \meta{coffin} \Arg{width} \Arg{total-height}
%   \end{syntax}
%   Resized the \meta{coffin} to \meta{width} and \meta{total-height},
%   both of which should be given as dimension expressions. These may
%   include the terms \cs{TotalHeight}, \cs{Height}, \cs{Depth} and 
%   \cs{Width}, which will evaluate to the appropriate dimensions of 
%   the \meta{coffin}.
% \end{function}
%
% \begin{function}{\coffin_scale:Nnn, \coffin_scale:cnn}
%   \begin{syntax}
%     \cs{coffin_scale:Nnn} \meta{coffin} \Arg{x-scale} \Arg{y-scale}
%   \end{syntax}
%   Scales the \meta{coffin} by a factors \meta{x-scale} and 
%   \meta{y-scale} in the horizontal and vertical directions, 
%   respectively. The two scale factors should be given as real numbers.
% \end{function}
% \end{documentation}
%
% \begin{implementation}
%
% \section{\pkg{l3coffins-scaling} Implementation}
% 
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%    
%    \begin{macrocode}
\ProvidesExplPackage
  {\ExplFileName}{\ExplFileDate}{\ExplFileVersion}{\ExplFileDescription}
%    \end{macrocode}
%
% \subsection{Resizing coffins}
%
% \begin{variable}{\l_coffin_scale_x_fp}
% \begin{variable}{\l_coffin_scale_y_fp}
%   Storage for the scaling factors in $x$ and $y$, respectively.
%    \begin{macrocode}
\fp_new:N \l_coffin_scale_x_fp
\fp_new:N \l_coffin_scale_y_fp
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \begin{variable}{\l_coffin_scaled_total_height_dim}
% \begin{variable}{\l_coffin_scaled_width_dim}
%   When scaling, the values given have to be turned into absolute values.
%    \begin{macrocode}
\dim_new:N \l_coffin_scaled_total_height_dim
\dim_new:N \l_coffin_scaled_width_dim
%    \end{macrocode}
% \end{variable}
% \end{variable}
%
% \begin{macro}{\coffin_resize:Nnn, \coffin_resize:cnn}
%   Resizing a coffin begins by setting up the user-friendly names for
%   the dimensions of the coffin box. The new sizes are then turned into
%   scale factor. This is the same operation as takes place for the 
%   underlying box, but that operation is grouped and so the same
%   calculation is done here.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \coffin_resize:Nnn #1#2#3
  {
    \coffin_set_user_dimensions:N #1
    \fp_set_from_dim:Nn \l_coffin_scale_x_fp {#2}
    \fp_set_from_dim:Nn \l_coffin_tmp_fp { \Width }
    \fp_div:Nn \l_coffin_scale_x_fp { \l_coffin_tmp_fp }
    \fp_set_from_dim:Nn \l_coffin_scale_y_fp {#3}
    \fp_set_from_dim:Nn \l_coffin_tmp_fp { \TotalHeight }
    \fp_div:Nn \l_coffin_scale_y_fp { \l_coffin_tmp_fp }
    \hbox_set:Nn #1 { \resizebox * {#2} {#3} { \box_use:N #1 } }
    \coffin_resize_common:Nnn #1 {#2} {#3}
  }
\cs_generate_variant:Nn \coffin_resize:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\coffin_resize_common:Nnn}
%   The poles and corners of the coffin are scaled to the appropriate
%   places before actually resizing the underlying box.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \coffin_resize_common:Nnn #1#2#3
  {
    \prop_map_inline:cn { l_coffin_corners_ \int_value:w #1 _prop }
      { \coffin_scale_corner:Nnnn #1 {##1} ##2 }
    \prop_map_inline:cn { l_coffin_poles_ \int_value:w #1 _prop }
      { \coffin_scale_pole:Nnnnnn #1 {##1} ##2 }
%    \end{macrocode}
%   Negative $x$-scaling values will place the poles in the wrong
%   location: this is corrected here.
%    \begin{macrocode}
    \fp_compare:NNNT \l_coffin_scale_x_fp < \c_zero_fp
      {
        \prop_map_inline:cn { l_coffin_corners_ \int_value:w #1 _prop }
          { \coffin_x_shift_corner:Nnnn #1 {##1} ##2 }
        \prop_map_inline:cn { l_coffin_poles_ \int_value:w #1 _prop }
          { \coffin_x_shift_pole:Nnnnnn #1 {##1} ##2 }
      }  
    \coffin_end_user_dimensions:
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\coffin_scale:Nnn, \coffin_scale:cnn}
%   For scaling, the opposite calculation is done to find the new
%   dimensions for the coffin. Only the total height is needed, as this
%   is the shift required for corners and poles. The scaling is done
%   the \TeX{} way as this works properly with floating point values
%   without needing to use the \texttt{fp} module.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \coffin_scale:Nnn #1#2#3
  {
    \coffin_set_user_dimensions:N #1
    \fp_set:Nn \l_coffin_scale_x_fp {#2}
    \fp_set:Nn \l_coffin_scale_y_fp {#3}
    \fp_compare:NNNTF \l_coffin_scale_y_fp > \c_zero_fp
      { \l_coffin_scaled_total_height_dim #3 \TotalHeight }
      { \l_coffin_scaled_total_height_dim -#3 \TotalHeight }
    \fp_compare:NNNTF \l_coffin_scale_x_fp > \c_zero_fp
      { \l_coffin_scaled_width_dim -#2 \Width }
      { \l_coffin_scaled_width_dim #2 \Width }
    \hbox_set:Nn #1 { \scalebox  {#2} [#3] { \box_use:N #1 } }
    \coffin_resize_common:Nnn #1 
      { \l_coffin_scaled_width_dim } { \l_coffin_scaled_total_height_dim }
  }
\cs_generate_variant:Nn \coffin_scale:Nnn { c }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\coffin_scale_vector:nnNN}
%   This functions scales a vector from the origin using the pre-set scale
%   factors in $x$ and $y$. This is a much less complex operation
%   than rotation, and as a result the code is a lot clearer.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \coffin_scale_vector:nnNN #1#2#3#4
  {
    \fp_set_from_dim:Nn \l_coffin_tmp_fp {#1}
    \fp_mul:Nn \l_coffin_tmp_fp { \l_coffin_scale_x_fp }
    \dim_set:Nn #3 { \fp_to_dim:N \l_coffin_tmp_fp }
    \fp_set_from_dim:Nn \l_coffin_tmp_fp {#2}
    \fp_mul:Nn \l_coffin_tmp_fp { \l_coffin_scale_y_fp }
    \dim_set:Nn #4 { \fp_to_dim:N \l_coffin_tmp_fp }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\coffin_scale_corner:Nnnn}
% \begin{macro}{\coffin_scale_pole:Nnnnnn}
%   Scaling both corners and poles is a simple calculation using the 
%   preceding vector scaling.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \coffin_scale_corner:Nnnn #1#2#3#4
  {
    \coffin_scale_vector:nnNN {#3} {#4} \l_coffin_x_dim \l_coffin_y_dim
    \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } {#2}
      { { \dim_use:N \l_coffin_x_dim } { \dim_use:N \l_coffin_y_dim } }  
  }
\cs_new_protected_nopar:Npn \coffin_scale_pole:Nnnnnn #1#2#3#4#5#6
  {
    \coffin_scale_vector:nnNN {#3} {#4} \l_coffin_x_dim \l_coffin_y_dim
    \coffin_set_pole:Nnx #1 {#2}
      {
        { \dim_use:N \l_coffin_x_dim } { \dim_use:N \l_coffin_y_dim }
        {#5} {#6}
      }  
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
% \begin{macro}{\coffin_x_shift_corner:Nnnn}
% \begin{macro}{\coffin_x_shift_pole:Nnnnnn}
%   These functions correct for the $x$ displacement that takes
%   place with a negative horizontal scaling.
%    \begin{macrocode}
\cs_new_protected_nopar:Npn \coffin_x_shift_corner:Nnnn #1#2#3#4
  {
    \prop_put:cnx { l_coffin_corners_ \int_value:w #1 _prop } {#2}
      { 
        { \dim_eval:n { #3 + \box_wd:N #1 } } {#4}
    }  
  }
\cs_new_protected_nopar:Npn \coffin_x_shift_pole:Nnnnnn #1#2#3#4#5#6
  {
    \prop_put:cnx { l_coffin_poles_ \int_value:w #1 _prop } {#2}
      {
        { \dim_eval:n #3 + \box_wd:N #1 } {#4} 
        {#5} {#6} 
      }
  }
%    \end{macrocode}
% \end{macro}
% \end{macro}
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
%
% \end{implementation}
%
% \PrintIndex