diff options
-rw-r--r-- | sc/source/core/data/drwlayer.cxx | 104 |
1 files changed, 76 insertions, 28 deletions
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())); } } } |