sc/source/core/data/drwlayer.cxx |  104 ++++++++++++++++++++++++++++-----------
 1 file changed, 76 insertions(+), 28 deletions(-)

New commits:
commit a63cd8bbe7cf881daa8dc7a7f32f3e5ac384e902
Author:     Armin Le Grand <armin.le.gr...@cib.de>
AuthorDate: Thu Nov 22 13:18:30 2018 +0100
Commit:     Thorsten Behrens <thorsten.behr...@cib.de>
CommitDate: Mon Nov 26 11:50:42 2018 +0100

    tdf#116931 Fix scale when calc cells move indirectly
    
    For the anchor mode 'To Cell (resize with cell)' there
    were errors e.g. when the cell the object is in does
    not scale but move. If that move went further than the
    object is, wrong offsets emerged.
    Also added full linear per-cell scale instead of only
    scale (no translation through scale). Overhauled to
    use liner transfomations, too.
    
    Change-Id: Icff0fad168476c68ea10fd5830bf53bd7294b89f
    Reviewed-on: https://gerrit.libreoffice.org/63803
    Tested-by: Jenkins
    Reviewed-by: Armin Le Grand <armin.le.gr...@cib.de>
    (cherry picked from commit 10a58ec15438d34a594437815882862c4576e2c0)
    Reviewed-on: https://gerrit.libreoffice.org/63851
    Reviewed-by: Thorsten Behrens <thorsten.behr...@cib.de>

diff --git a/sc/source/core/data/drwlayer.cxx b/sc/source/core/data/drwlayer.cxx
index dc24b9e0d410..540e320d1999 100644
--- a/sc/source/core/data/drwlayer.cxx
+++ b/sc/source/core/data/drwlayer.cxx
@@ -642,11 +642,15 @@ void ScDrawLayer::ResizeLastRectFromAnchor(const 
SdrObject* pObj, ScDrawObjData&
     aPos.setX(TwipsToHmm(aPos.X()));
     aPos.setY(TwipsToHmm(aPos.Y()));
     aPos += lcl_calcAvailableDiff(*pDoc, nCol1, nRow1, nTab1, 
rData.maStartOffset);
+
+    // this sets the needed changed position (translation)
     aRect.SetPos(aPos);
 
     if (bCanResize)
     {
-        tools::Rectangle aLastCellRect = rData.getLastCellRect();
+        // all this stuff is additional stuff to evtl. not only translate the
+        // range (Rectangle), but also check for and evtl. do corrections for 
it's size
+        const tools::Rectangle aLastCellRect(rData.getLastCellRect());
 
         // If the row was hidden before, or we don't have a valid cell rect, 
calculate the
         // new rect based on the end point.
@@ -666,61 +670,105 @@ void ScDrawLayer::ResizeLastRectFromAnchor(const 
SdrObject* pObj, ScDrawObjData&
             // We calculate based on the last cell rect to be able to scale 
the image
             // as much as the cell was scaled.
             // Still, we keep the image in its current cell (to keep start 
anchor == end anchor)
-            tools::Rectangle aCurrentCellRect = GetCellRect(*GetDocument(), 
rData.maStart, true);
-            double fWidthFactor = 
static_cast<double>(aCurrentCellRect.GetWidth())
-                                  / 
static_cast<double>(aLastCellRect.GetWidth());
-            double fHeightFactor = 
static_cast<double>(aCurrentCellRect.GetHeight())
-                                   / 
static_cast<double>(aLastCellRect.GetHeight());
+            const tools::Rectangle 
aCurrentCellRect(GetCellRect(*GetDocument(), rData.maStart, true));
+            long nCurrentWidth(aCurrentCellRect.GetWidth());
+            long nCurrentHeight(aCurrentCellRect.GetHeight());
+            const long nLastWidth(aLastCellRect.GetWidth());
+            const long nLastHeight(aLastCellRect.GetHeight());
+
+            // tdf#116931 Avoid and correct nifty numerical problems with the 
integer
+            // based and converted values (GetCellRect uses multiplies with 
HMM_PER_TWIPS)
+            if(nCurrentWidth + 1 == nLastWidth || nCurrentWidth == nLastWidth 
+ 1)
+            {
+                nCurrentWidth = nLastWidth;
+            }
 
-            bool bIsGrowingLarger = aLastCellRect.GetWidth() * 
aLastCellRect.GetHeight()
-                                    < aCurrentCellRect.GetWidth() * 
aCurrentCellRect.GetHeight();
+            if(nCurrentHeight + 1 == nLastHeight || nCurrentHeight == 
nLastHeight + 1)
+            {
+                nCurrentHeight = nLastHeight;
+            }
 
-            if (pObj->shouldKeepAspectRatio())
+            // get intial ScalingFactors
+            double fWidthFactor(nCurrentWidth == nLastWidth || 0 == nLastWidth
+                ? 1.0
+                : static_cast<double>(nCurrentWidth) / 
static_cast<double>(nLastWidth));
+            double fHeightFactor(nCurrentHeight == nLastHeight || 0 == 
nLastHeight
+                ? 1.0
+                : static_cast<double>(nCurrentHeight) / 
static_cast<double>(nLastHeight));
+
+            // check if we grow or shrink - and at all
+            const bool bIsGrowing(nCurrentWidth > nLastWidth || nCurrentHeight 
> nLastHeight);
+            const bool bIsShrinking(nCurrentWidth < nLastWidth || 
nCurrentHeight < nLastHeight);
+            const bool bIsSizeChanged(bIsGrowing || bIsShrinking);
+
+            // handle AspectRatio, only needed if size does change
+            if(bIsSizeChanged && pObj->shouldKeepAspectRatio())
             {
                 tools::Rectangle aRectIncludingOffset = aRect;
                 aRectIncludingOffset.setWidth(aRect.GetWidth() + 
rData.maStartOffset.X());
                 aRectIncludingOffset.setHeight(aRect.GetHeight() + 
rData.maStartOffset.Y());
                 long nWidth = aRectIncludingOffset.GetWidth();
                 assert(nWidth && "div-by-zero");
-                double fMaxWidthFactor = 
static_cast<double>(aCurrentCellRect.GetWidth())
+                double fMaxWidthFactor = static_cast<double>(nCurrentWidth)
                                          / static_cast<double>(nWidth);
                 long nHeight = aRectIncludingOffset.GetHeight();
                 assert(nHeight && "div-by-zero");
-                double fMaxHeightFactor = 
static_cast<double>(aCurrentCellRect.GetHeight())
+                double fMaxHeightFactor = static_cast<double>(nCurrentHeight)
                                           / static_cast<double>(nHeight);
                 double fMaxFactor = std::min(fMaxHeightFactor, 
fMaxWidthFactor);
 
-                if (bIsGrowingLarger) // cell is growing larger
+                if(bIsGrowing) // cell is growing larger
                 {
                     // To actually grow the image, we need to take the max
                     fWidthFactor = fHeightFactor = std::max(fWidthFactor, 
fHeightFactor);
                 }
-                else // cell is growing smaller, take the min
+                else if(bIsShrinking) // cell is growing smaller, take the min
                 {
                     fWidthFactor = fHeightFactor = std::min(fWidthFactor, 
fHeightFactor);
                 }
+
                 // We don't want the image to become larger than the current 
cell
                 fWidthFactor = fHeightFactor = std::min(fWidthFactor, 
fMaxFactor);
             }
 
-            // When shrinking the cell, and the image still fits in the 
smaller cell, don't resize it at all
-            if (bIsGrowingLarger
-                || rData.getShapeRect().GetUnion(aCurrentCellRect) != 
aCurrentCellRect)
+            if(bIsSizeChanged)
             {
-                aRect.setWidth(
-                    rtl::math::round(static_cast<double>(aRect.GetWidth()) * 
fWidthFactor));
-                aRect.setHeight(
-                    rtl::math::round(static_cast<double>(aRect.GetHeight()) * 
fHeightFactor));
+                // tdf#116931 re-organized scaling (if needed)
+                // Check if we need to scale at all. Always scale on growing.
+                bool bNeedToScale(bIsGrowing);
+
+                if(!bNeedToScale && bIsShrinking)
+                {
+                    // Check if original still fits into space. Do *not* 
forget to
+                    // compare with evtl. numerically corrected 
aCurrentCellRect
+                    const bool bFitsInX(aRect.Right() <= 
aCurrentCellRect.Left() + nCurrentWidth);
+                    const bool bFitsInY(aRect.Bottom() <= 
aCurrentCellRect.Top() + nCurrentHeight);
+
+                    // If the image still fits in the smaller cell, don't 
resize it at all
+                    bNeedToScale = (!bFitsInX || !bFitsInY);
+                }
 
-                // Reduce offset also when shrinking
-                if (!bIsGrowingLarger)
+                if(bNeedToScale)
                 {
-                    Point aAvailableSpaceInCell = Point(aRect.getX() - 
aLastCellRect.TopLeft().X(),
-                                                        aRect.getY() - 
aLastCellRect.TopLeft().Y());
-                    
aRect.setX(rtl::math::round(static_cast<double>(aRect.getX())
-                                                + aAvailableSpaceInCell.X() * 
fWidthFactor));
-                    
aRect.setY(rtl::math::round(static_cast<double>(aRect.getY())
-                                                + aAvailableSpaceInCell.Y() * 
fHeightFactor));
+                    // tdf#116931 use transformations now. Translation is 
already applied
+                    // (see aRect.SetPos above), so only scale needs to be 
applied - relative
+                    // to *new* CellRect (which is aCurrentCellRect).
+                    // Prepare scale relative to top-left of aCurrentCellRect
+                    basegfx::B2DHomMatrix aChange;
+
+                    aChange.translate(-aCurrentCellRect.getX(), 
-aCurrentCellRect.getY());
+                    aChange.scale(fWidthFactor, fHeightFactor);
+                    aChange.translate(aCurrentCellRect.getX(), 
aCurrentCellRect.getY());
+
+                    // create B2DRange and transform by prepared scale
+                    basegfx::B2DRange aNewRange(aRect.Left(), aRect.Top(), 
aRect.Right(), aRect.Bottom());
+
+                    aNewRange.transform(aChange);
+
+                    // apply to aRect
+                    aRect = tools::Rectangle(
+                        basegfx::fround(aNewRange.getMinX()), 
basegfx::fround(aNewRange.getMinY()),
+                        basegfx::fround(aNewRange.getMaxX()), 
basegfx::fround(aNewRange.getMaxY()));
                 }
             }
         }
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to