[Libreoffice-commits] core.git: 11 commits - basegfx/source editeng/source include/basegfx include/editeng include/svx svx/source sw/source

Armin Le Grand Armin.Le.Grand at cib.de
Sat Nov 18 12:08:54 UTC 2017


 basegfx/source/numeric/ftools.cxx  |   34 ++++
 editeng/source/items/frmitems.cxx  |   16 +
 include/basegfx/numeric/ftools.hxx |   20 ++
 include/editeng/brushitem.hxx      |    2 
 include/svx/svdobj.hxx             |    7 
 svx/source/svdraw/svddrgmt.cxx     |   20 --
 svx/source/svdraw/svdobj.cxx       |   10 -
 svx/source/uitest/sdrobject.cxx    |   16 -
 sw/source/core/doc/notxtfrm.cxx    |  274 ++++++++++++++++++++++++++++++----
 sw/source/core/draw/dflyobj.cxx    |  298 ++++++++++++++++++++++++++++---------
 sw/source/core/frmedt/fefly1.cxx   |   19 ++
 sw/source/core/inc/dflyobj.hxx     |    4 
 sw/source/core/inc/flyfrms.hxx     |   31 +++
 sw/source/core/inc/frame.hxx       |   78 +++++++++
 sw/source/core/inc/frmtool.hxx     |    5 
 sw/source/core/inc/notxtfrm.hxx    |   24 ++
 sw/source/core/layout/fly.cxx      |  210 ++++++++++++++++----------
 sw/source/core/layout/flycnt.cxx   |    2 
 sw/source/core/layout/flylay.cxx   |  194 +++++++++++++++++++++++-
 sw/source/core/layout/frmtool.cxx  |   20 +-
 sw/source/core/layout/pagechg.cxx  |   16 -
 sw/source/core/layout/paintfrm.cxx |   12 +
 sw/source/core/layout/wsfrm.cxx    |  186 +++++++++++++++++++++++
 sw/source/core/text/txtfly.cxx     |   17 +-
 24 files changed, 1280 insertions(+), 235 deletions(-)

New commits:
commit 0557a9aace85b7d47f77de758bb4f9f97303d07c
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Fri Nov 17 18:47:07 2017 +0100

    RotateFlyFrame3: Corrected wrong static_cast
    
    Change-Id: Ia3e0748d0b4ba11ec84a85e823472cdac9bf987a

diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index 569a0ec86282..8f440743b736 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -2447,8 +2447,6 @@ bool SwFlyFrame::GetContour( tools::PolyPolygon&   rContour,
 
     if(bIsCandidate)
     {
-        const SwFlyFreeFrame* pSwFlyFreeFrame(static_cast< const SwFlyFreeFrame* >(this));
-
         if(GetFormat()->GetSurround().IsContour())
         {
             SwNoTextNode *pNd = const_cast<SwNoTextNode*>(static_cast<const SwNoTextNode*>(static_cast<const SwContentFrame*>(Lower())->GetNode()));
@@ -2543,6 +2541,8 @@ bool SwFlyFrame::GetContour( tools::PolyPolygon&   rContour,
         }
         else
         {
+            const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(this));
+
             if(nullptr != pSwFlyFreeFrame &&
                 pSwFlyFreeFrame->supportsAutoContour() &&
                 // isTransformableSwFrame already used in supportsAutoContour(), but
@@ -2558,27 +2558,29 @@ bool SwFlyFrame::GetContour( tools::PolyPolygon&   rContour,
             }
         }
 
-        if(bRet &&
-            0 != rContour.Count() &&
-            nullptr != pSwFlyFreeFrame &&
-            pSwFlyFreeFrame->isTransformableSwFrame())
+        if(bRet && 0 != rContour.Count())
         {
-            // Need to adapt contour to transformation
-            basegfx::B2DVector aScale, aTranslate;
-            double fRotate, fShearX;
-            getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+            const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(this));
 
-            if(!basegfx::fTools::equalZero(fRotate))
+            if(nullptr != pSwFlyFreeFrame && pSwFlyFreeFrame->isTransformableSwFrame())
             {
-                basegfx::B2DPolyPolygon aSource(rContour.getB2DPolyPolygon());
-                const basegfx::B2DPoint aCenter(getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
-                const basegfx::B2DHomMatrix aRotateAroundCenter(
-                    basegfx::utils::createRotateAroundPoint(
-                        aCenter.getX(),
-                        aCenter.getY(),
-                        fRotate));
-                aSource.transform(aRotateAroundCenter);
-                rContour = tools::PolyPolygon(aSource);
+                // Need to adapt contour to transformation
+                basegfx::B2DVector aScale, aTranslate;
+                double fRotate, fShearX;
+                getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+                if(!basegfx::fTools::equalZero(fRotate))
+                {
+                    basegfx::B2DPolyPolygon aSource(rContour.getB2DPolyPolygon());
+                    const basegfx::B2DPoint aCenter(getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
+                    const basegfx::B2DHomMatrix aRotateAroundCenter(
+                        basegfx::utils::createRotateAroundPoint(
+                            aCenter.getX(),
+                            aCenter.getY(),
+                            fRotate));
+                    aSource.transform(aRotateAroundCenter);
+                    rContour = tools::PolyPolygon(aSource);
+                }
             }
         }
     }
commit 487ac20ecd73cf3d98071ba30cf5597d957017f7
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Nov 16 18:47:29 2017 +0100

    RotateFlyFrame3: add support for AutoContour
    
    For transformed FlyFrames with no Border and no Padding it
    would be nice to immediately start using AutoContour, added
    first implementation to do so.
    Added several conditions for AutoContour, need to
    work on reaction on changes to these. Corrected
    needed transform adaptions to Contour(s)
    
    Change-Id: Ia3d7845fd5d50c8a413d592ae07ce2041ccc91b9

diff --git a/editeng/source/items/frmitems.cxx b/editeng/source/items/frmitems.cxx
index c2bfc5e290fb..bb61ccaccc86 100644
--- a/editeng/source/items/frmitems.cxx
+++ b/editeng/source/items/frmitems.cxx
@@ -3157,6 +3157,22 @@ SvxBrushItem::~SvxBrushItem()
 {
 }
 
+bool SvxBrushItem::isUsed() const
+{
+    if (GPOS_NONE != GetGraphicPos())
+    {
+        // graphic used
+        return true;
+    }
+    else if (0xff != GetColor().GetTransparency())
+    {
+        // color used
+        return true;
+    }
+
+    return false;
+}
+
 sal_uInt16 SvxBrushItem::GetVersion( sal_uInt16 /*nFileVersion*/ ) const
 {
     return BRUSH_GRAPHIC_VERSION;
diff --git a/include/editeng/brushitem.hxx b/include/editeng/brushitem.hxx
index 516abdacd467..8aa177aa2adb 100644
--- a/include/editeng/brushitem.hxx
+++ b/include/editeng/brushitem.hxx
@@ -79,6 +79,8 @@ public:
     virtual ~SvxBrushItem() override;
 
 public:
+    // check if it's used
+    bool isUsed() const;
 
     virtual bool GetPresentation( SfxItemPresentation ePres,
                                   MapUnit eCoreMetric,
diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 93103489af70..1ebb9aaf0944 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -1308,15 +1308,47 @@ void SwNoTextFrame::PaintPicture( vcl::RenderContext* pOut, const SwRect &rGrfAr
 bool SwNoTextFrame::IsTransparent() const
 {
     const SwViewShell* pSh = getRootFrame()->GetCurrShell();
+
     if ( !pSh || !pSh->GetViewOptions()->IsGraphic() )
+    {
         return true;
+    }
 
     const SwGrfNode *pNd;
+
     if( nullptr != (pNd = GetNode()->GetGrfNode()) )
-        return pNd->IsTransparent();
+    {
+        if(pNd->IsTransparent())
+        {
+            return true;
+        }
+    }
+
+    // RotateFlyFrame3: If we are transformed, there are 'free' areas between
+    // the Graphic and the Border/Padding stuff - at least as long as those
+    // (Border and Padding) are not transformed, too
+    if(isTransformableSwFrame())
+    {
+        // we can be more specific - rotations of multiples of
+        // 90 degrees will leave no gaps. Go from [0.0 .. F_2PI]
+        // to [0 .. 360] and check modulo 90
+        const long nRot(static_cast<long>(getLocalFrameRotation() / F_PI180));
+        const bool bMultipleOf90(0 == (nRot % 90));
+
+        if(!bMultipleOf90)
+        {
+            return true;
+        }
+    }
 
     //#29381# OLE are always transparent
-    return true;
+    if(nullptr != GetNode()->GetOLENode())
+    {
+        return true;
+    }
+
+    // return false by default to avoid background paint
+    return false;
 }
 
 void SwNoTextFrame::StopAnimation( OutputDevice* pOut ) const
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index a4466f1f9085..2dd8cffbf300 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -632,9 +632,9 @@ void SwVirtFlyDrawObj::NbcSetLogicRect(const tools::Rectangle& )
 //  SwVirtFlyDrawObj::Move() and Resize()
 void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
 {
-    if(GetFlyFrame()->IsFlyFreeFrame() && static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame())
+    if(GetFlyFrame()->IsFlyFreeFrame() && static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame())
     {
-        // When we have a change and are in transformed state (e.g. rotation used),
+        // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used),
         // we need to fall back to the un-transformed state to keep the old code below
         // working properly. Restore FrameArea and use aOutRect from old FrameArea.
         TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
@@ -825,7 +825,7 @@ void SwVirtFlyDrawObj::NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, dou
 
     const bool bIsTransformableSwFrame(
         GetFlyFrame()->IsFlyFreeFrame() &&
-        static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
+        static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame());
 
     if(bIsTransformableSwFrame)
     {
@@ -977,7 +977,7 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef, const Fraction& xFact, const
     const bool bUseRightEdge((bVertX && !bVertL2RX ) || bRTL);
     const bool bIsTransformableSwFrame(
         GetFlyFrame()->IsFlyFreeFrame() &&
-        static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
+        static_cast< SwFlyFreeFrame* >(GetFlyFrame())->isTransformableSwFrame());
 
     if(bIsTransformableSwFrame)
     {
diff --git a/sw/source/core/frmedt/fefly1.cxx b/sw/source/core/frmedt/fefly1.cxx
index 105689dbf848..ece412fde57c 100644
--- a/sw/source/core/frmedt/fefly1.cxx
+++ b/sw/source/core/frmedt/fefly1.cxx
@@ -369,7 +369,7 @@ void SwFEShell::SetFlyPos( const Point& rAbsPos )
     // Anchor and new RelPos will be calculated and set by the Fly
     if ( pFly->IsFlyAtContentFrame() )
     {
-        if(pFly->IsFlyFreeFrame() && static_cast<SwFlyFreeFrame*>(pFly)->isTransformableSwFrame())
+        if(pFly->IsFlyFreeFrame() && static_cast< SwFlyFreeFrame* >(pFly)->isTransformableSwFrame())
         {
             // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used),
             // we need to correct the absolute position (rAbsPos) which was created in
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index eaae5b89059d..1bde38f6784b 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -37,10 +37,10 @@ private:
     // #i34753# - flag for at-page anchored Writer fly frames
     // to prevent a positioning - call of method <MakeObjPos()> -, if Writer
     // fly frame is already clipped during its format by the object formatter.
-    bool mbNoMakePos;
+    bool            mbNoMakePos : 1;
 
     // #i37068# - flag to prevent move in method <CheckClip(..)>
-    bool mbNoMoveOnCheckClip;
+    bool            mbNoMoveOnCheckClip : 1;
 
     SwRect maUnclippedFrame;
 
@@ -134,6 +134,9 @@ public:
     TransformableSwFrame* getTransformableSwFrame() { return mpTransformableSwFrame.get(); }
     const TransformableSwFrame* getTransformableSwFrame() const { return mpTransformableSwFrame.get(); }
 
+    // RotateFlyFrame3 - Support for AutoContour
+    bool supportsAutoContour() const;
+
     // RotateFlyFrame3 - Support for Transformations
     virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const override;
     virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const override;
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index 5163fbb3f3c4..569a0ec86282 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -2303,8 +2303,18 @@ void SwFlyFrame::NotifyDrawObj()
     pObj->SetRectsDirty();
     pObj->SetChanged();
     pObj->BroadcastObjectChange();
+
     if ( GetFormat()->GetSurround().IsContour() )
+    {
+        ClrContourCache( pObj );
+    }
+    else if(IsFlyFreeFrame() && static_cast< const SwFlyFreeFrame* >(this)->supportsAutoContour())
+    {
+        // RotateFlyFrame3: Also need to clear when changes happen
+        // Caution: isTransformableSwFrame is already reset when resetting rotation, so
+        // *additionally* reset in SwFlyFreeFrame::MakeAll when no more rotation
         ClrContourCache( pObj );
+    }
 }
 
 Size SwFlyFrame::CalcRel( const SwFormatFrameSize &rSz ) const
@@ -2435,120 +2445,141 @@ bool SwFlyFrame::GetContour( tools::PolyPolygon&   rContour,
     bool bRet = false;
     const bool bIsCandidate(Lower() && Lower()->IsNoTextFrame());
 
-    if(bIsCandidate && GetFormat()->GetSurround().IsContour())
+    if(bIsCandidate)
     {
-        SwNoTextNode *pNd = const_cast<SwNoTextNode*>(static_cast<const SwNoTextNode*>(static_cast<const SwContentFrame*>(Lower())->GetNode()));
-        // OD 16.04.2003 #i13147# - determine <GraphicObject> instead of <Graphic>
-        // in order to avoid load of graphic, if <SwNoTextNode> contains a graphic
-        // node and method is called for paint.
-        const GraphicObject* pGrfObj = nullptr;
-        bool bGrfObjCreated = false;
-        const SwGrfNode* pGrfNd = pNd->GetGrfNode();
-        if ( pGrfNd && _bForPaint )
-        {
-            pGrfObj = &(pGrfNd->GetGrfObj());
-        }
-        else
-        {
-            pGrfObj = new GraphicObject( pNd->GetGraphic() );
-            bGrfObjCreated = true;
-        }
-        OSL_ENSURE( pGrfObj, "SwFlyFrame::GetContour() - No Graphic/GraphicObject found at <SwNoTextNode>." );
-        if ( pGrfObj && pGrfObj->GetType() != GraphicType::NONE )
+        const SwFlyFreeFrame* pSwFlyFreeFrame(static_cast< const SwFlyFreeFrame* >(this));
+
+        if(GetFormat()->GetSurround().IsContour())
         {
-            if( !pNd->HasContour() )
+            SwNoTextNode *pNd = const_cast<SwNoTextNode*>(static_cast<const SwNoTextNode*>(static_cast<const SwContentFrame*>(Lower())->GetNode()));
+            // OD 16.04.2003 #i13147# - determine <GraphicObject> instead of <Graphic>
+            // in order to avoid load of graphic, if <SwNoTextNode> contains a graphic
+            // node and method is called for paint.
+            const GraphicObject* pGrfObj = nullptr;
+            bool bGrfObjCreated = false;
+            const SwGrfNode* pGrfNd = pNd->GetGrfNode();
+            if ( pGrfNd && _bForPaint )
+            {
+                pGrfObj = &(pGrfNd->GetGrfObj());
+            }
+            else
             {
-                // OD 16.04.2003 #i13147# - no <CreateContour> for a graphic
-                // during paint. Thus, return (value of <bRet> should be <false>).
-                if ( pGrfNd && _bForPaint )
+                pGrfObj = new GraphicObject( pNd->GetGraphic() );
+                bGrfObjCreated = true;
+            }
+            OSL_ENSURE( pGrfObj, "SwFlyFrame::GetContour() - No Graphic/GraphicObject found at <SwNoTextNode>." );
+            if ( pGrfObj && pGrfObj->GetType() != GraphicType::NONE )
+            {
+                if( !pNd->HasContour() )
                 {
-                    OSL_FAIL( "SwFlyFrame::GetContour() - No Contour found at <SwNoTextNode> during paint." );
-                    return bRet;
+                    // OD 16.04.2003 #i13147# - no <CreateContour> for a graphic
+                    // during paint. Thus, return (value of <bRet> should be <false>).
+                    if ( pGrfNd && _bForPaint )
+                    {
+                        OSL_FAIL( "SwFlyFrame::GetContour() - No Contour found at <SwNoTextNode> during paint." );
+                        return bRet;
+                    }
+                    pNd->CreateContour();
                 }
-                pNd->CreateContour();
-            }
-            pNd->GetContour( rContour );
-            // The Node holds the Polygon matching the original size of the graphic
-            // We need to include the scaling here
-            SwRect aClip;
-            SwRect aOrig;
-            Lower()->Calc(pRenderContext);
-            static_cast<const SwNoTextFrame*>(Lower())->GetGrfArea( aClip, &aOrig );
-            // OD 16.04.2003 #i13147# - copy method code <SvxContourDlg::ScaleContour(..)>
-            // in order to avoid that graphic has to be loaded for contour scale.
-            //SvxContourDlg::ScaleContour( rContour, aGrf, MapUnit::MapTwip, aOrig.SSize() );
-            {
-                OutputDevice*   pOutDev = Application::GetDefaultDevice();
-                const MapMode   aDispMap( MapUnit::MapTwip );
-                const MapMode   aGrfMap( pGrfObj->GetPrefMapMode() );
-                const Size      aGrfSize( pGrfObj->GetPrefSize() );
-                Size            aOrgSize;
-                Point           aNewPoint;
-                bool            bPixelMap = aGrfMap.GetMapUnit() == MapUnit::MapPixel;
-
-                if ( bPixelMap )
-                    aOrgSize = pOutDev->PixelToLogic( aGrfSize, aDispMap );
-                else
-                    aOrgSize = OutputDevice::LogicToLogic( aGrfSize, aGrfMap, aDispMap );
-
-                if ( aOrgSize.Width() && aOrgSize.Height() )
+                pNd->GetContour( rContour );
+                // The Node holds the Polygon matching the original size of the graphic
+                // We need to include the scaling here
+                SwRect aClip;
+                SwRect aOrig;
+                Lower()->Calc(pRenderContext);
+                static_cast<const SwNoTextFrame*>(Lower())->GetGrfArea( aClip, &aOrig );
+                // OD 16.04.2003 #i13147# - copy method code <SvxContourDlg::ScaleContour(..)>
+                // in order to avoid that graphic has to be loaded for contour scale.
+                //SvxContourDlg::ScaleContour( rContour, aGrf, MapUnit::MapTwip, aOrig.SSize() );
                 {
-                    double fScaleX = (double) aOrig.Width() / aOrgSize.Width();
-                    double fScaleY = (double) aOrig.Height() / aOrgSize.Height();
+                    OutputDevice*   pOutDev = Application::GetDefaultDevice();
+                    const MapMode   aDispMap( MapUnit::MapTwip );
+                    const MapMode   aGrfMap( pGrfObj->GetPrefMapMode() );
+                    const Size      aGrfSize( pGrfObj->GetPrefSize() );
+                    Size            aOrgSize;
+                    Point           aNewPoint;
+                    bool            bPixelMap = aGrfMap.GetMapUnit() == MapUnit::MapPixel;
+
+                    if ( bPixelMap )
+                        aOrgSize = pOutDev->PixelToLogic( aGrfSize, aDispMap );
+                    else
+                        aOrgSize = OutputDevice::LogicToLogic( aGrfSize, aGrfMap, aDispMap );
 
-                    for ( sal_uInt16 j = 0, nPolyCount = rContour.Count(); j < nPolyCount; j++ )
+                    if ( aOrgSize.Width() && aOrgSize.Height() )
                     {
-                        tools::Polygon& rPoly = rContour[ j ];
+                        double fScaleX = (double) aOrig.Width() / aOrgSize.Width();
+                        double fScaleY = (double) aOrig.Height() / aOrgSize.Height();
 
-                        for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ )
+                        for ( sal_uInt16 j = 0, nPolyCount = rContour.Count(); j < nPolyCount; j++ )
                         {
-                            if ( bPixelMap )
-                                aNewPoint = pOutDev->PixelToLogic( rPoly[ i ], aDispMap  );
-                            else
-                                aNewPoint = OutputDevice::LogicToLogic( rPoly[ i ], aGrfMap, aDispMap  );
+                            tools::Polygon& rPoly = rContour[ j ];
+
+                            for ( sal_uInt16 i = 0, nCount = rPoly.GetSize(); i < nCount; i++ )
+                            {
+                                if ( bPixelMap )
+                                    aNewPoint = pOutDev->PixelToLogic( rPoly[ i ], aDispMap  );
+                                else
+                                    aNewPoint = OutputDevice::LogicToLogic( rPoly[ i ], aGrfMap, aDispMap  );
 
-                            rPoly[ i ] = Point( FRound( aNewPoint.getX() * fScaleX ), FRound( aNewPoint.getY() * fScaleY ) );
+                                rPoly[ i ] = Point( FRound( aNewPoint.getX() * fScaleX ), FRound( aNewPoint.getY() * fScaleY ) );
+                            }
                         }
                     }
                 }
+                // OD 17.04.2003 #i13147# - destroy created <GraphicObject>.
+                if ( bGrfObjCreated )
+                {
+                    delete pGrfObj;
+                }
+                rContour.Move( aOrig.Left(), aOrig.Top() );
+                if( !aClip.Width() )
+                    aClip.Width( 1 );
+                if( !aClip.Height() )
+                    aClip.Height( 1 );
+                rContour.Clip( aClip.SVRect() );
+                rContour.Optimize(PolyOptimizeFlags::CLOSE);
+                bRet = true;
             }
-            // OD 17.04.2003 #i13147# - destroy created <GraphicObject>.
-            if ( bGrfObjCreated )
+        }
+        else
+        {
+            if(nullptr != pSwFlyFreeFrame &&
+                pSwFlyFreeFrame->supportsAutoContour() &&
+                // isTransformableSwFrame already used in supportsAutoContour(), but
+                // better check twice when it may get changed there...
+                pSwFlyFreeFrame->isTransformableSwFrame())
             {
-                delete pGrfObj;
+                // RotateFlyFrame: use untransformed SwFrame to allow text floating around.
+                // Will be transformed below
+                const TransformableSwFrame* pTransformableSwFrame(pSwFlyFreeFrame->getTransformableSwFrame());
+                const SwRect aFrameArea(pTransformableSwFrame->getUntransformedFrameArea());
+                rContour = tools::PolyPolygon(tools::Polygon(aFrameArea.SVRect()));
+                bRet = (0 != rContour.Count());
             }
-            rContour.Move( aOrig.Left(), aOrig.Top() );
-            if( !aClip.Width() )
-                aClip.Width( 1 );
-            if( !aClip.Height() )
-                aClip.Height( 1 );
-            rContour.Clip( aClip.SVRect() );
-            rContour.Optimize(PolyOptimizeFlags::CLOSE);
-            bRet = true;
         }
-    }
 
-    if(bRet &&
-        rContour.Count() &&
-        IsFlyFreeFrame() &&
-        static_cast<const SwFlyFreeFrame*>(this)->isTransformableSwFrame())
-    {
-        // RotateFlyFrame: Need to adapt contour to transformation
-        basegfx::B2DVector aScale, aTranslate;
-        double fRotate, fShearX;
-        getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
-
-        if(!basegfx::fTools::equalZero(fRotate))
-        {
-            basegfx::B2DPolyPolygon aSource(rContour.getB2DPolyPolygon());
-            const basegfx::B2DPoint aCenter(getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
-            const basegfx::B2DHomMatrix aRotateAroundCenter(
-                basegfx::utils::createRotateAroundPoint(
-                    aCenter.getX(),
-                    aCenter.getY(),
-                    fRotate));
-            aSource.transform(aRotateAroundCenter);
-            rContour = tools::PolyPolygon(aSource);
+        if(bRet &&
+            0 != rContour.Count() &&
+            nullptr != pSwFlyFreeFrame &&
+            pSwFlyFreeFrame->isTransformableSwFrame())
+        {
+            // Need to adapt contour to transformation
+            basegfx::B2DVector aScale, aTranslate;
+            double fRotate, fShearX;
+            getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+            if(!basegfx::fTools::equalZero(fRotate))
+            {
+                basegfx::B2DPolyPolygon aSource(rContour.getB2DPolyPolygon());
+                const basegfx::B2DPoint aCenter(getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
+                const basegfx::B2DHomMatrix aRotateAroundCenter(
+                    basegfx::utils::createRotateAroundPoint(
+                        aCenter.getX(),
+                        aCenter.getY(),
+                        fRotate));
+                aSource.transform(aRotateAroundCenter);
+                rContour = tools::PolyPolygon(aSource);
+            }
         }
     }
 
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
index 8a8c714ef351..8f6452b9b874 100644
--- a/sw/source/core/layout/flylay.cxx
+++ b/sw/source/core/layout/flylay.cxx
@@ -27,6 +27,7 @@
 #include <hints.hxx>
 #include <sectfrm.hxx>
 #include <notxtfrm.hxx>
+#include <txtfly.hxx>
 
 #include <svx/svdpage.hxx>
 #include <editeng/ulspitem.hxx>
@@ -42,6 +43,7 @@
 #include <IDocumentSettingAccess.hxx>
 #include <IDocumentDrawModelAccess.hxx>
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
 
 using namespace ::com::sun::star;
 
@@ -87,6 +89,8 @@ void SwFlyFreeFrame::DestroyImpl()
 
 SwFlyFreeFrame::~SwFlyFreeFrame()
 {
+    // we are possibly in ContourCache, make sure we vanish
+    ::ClrContourCache(GetVirtDrawObj());
 }
 
 // #i28701#
@@ -268,6 +272,14 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
     }
     else
     {
+        // RotateFlyFrame3: Also need to clear ContourCache (if used),
+        // usually done in SwFlyFrame::NotifyDrawObj, but there relies on
+        // being in transform mode which is already resetted then
+        if(isTransformableSwFrame())
+        {
+            ::ClrContourCache(GetVirtDrawObj());
+        }
+
         // reset transformations to show that they are not used
         mpTransformableSwFrame.reset();
     }
@@ -283,6 +295,65 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
 #endif
 }
 
+bool SwFlyFreeFrame::supportsAutoContour() const
+{
+    if(!isTransformableSwFrame())
+    {
+        // support only when transformed, else there is no free space
+        return false;
+    }
+
+    // Check for Borders. If we have Borders, do (currently) not support,
+    // since borders do not transform with the object.
+    // (Will need to be enhanced to take into account if we have Borders and if these
+    // transform with the object)
+    SwBorderAttrAccess aAccess(SwFrame::GetCache(), this);
+    const SwBorderAttrs &rAttrs(*aAccess.Get());
+
+    if(rAttrs.IsLine())
+    {
+        return false;
+    }
+
+    // Check for Padding. Do not support when padding is used, this will
+    // produce a covered space around the object (filled with fill defines)
+    const SfxPoolItem* pItem(nullptr);
+
+    if(GetFormat() && SfxItemState::SET == GetFormat()->GetItemState(RES_BOX, false, &pItem))
+    {
+        const SvxBoxItem& rBox = *static_cast< const SvxBoxItem* >(pItem);
+
+        if(rBox.HasBorder(/*bTreatPaddingAsBorder*/true))
+        {
+            return false;
+        }
+    }
+
+    // check for Fill - if we have fill, it will fill the gaps and we will not
+    // support AutoContour
+    if(GetFormat() && GetFormat()->supportsFullDrawingLayerFillAttributeSet())
+    {
+        const drawinglayer::attribute::SdrAllFillAttributesHelperPtr aFillAttributes(GetFormat()->getSdrAllFillAttributesHelper());
+
+        if(aFillAttributes.get() && aFillAttributes->isUsed())
+        {
+            return false;
+        }
+    }
+    else
+    {
+        const SvxBrushItem aBack(GetFormat()->makeBackgroundBrushItem());
+
+        if(aBack.isUsed())
+        {
+            return false;
+        }
+    }
+
+    // else, support
+    return true;
+}
+
 // RotateFlyFrame3 - Support for Transformations - outer frame
 basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
 {
diff --git a/sw/source/core/layout/frmtool.cxx b/sw/source/core/layout/frmtool.cxx
index 7144ee460dcd..2276f7fa2b99 100644
--- a/sw/source/core/layout/frmtool.cxx
+++ b/sw/source/core/layout/frmtool.cxx
@@ -2740,11 +2740,23 @@ void Notify( SwFlyFrame *pFly, SwPageFrame *pOld, const SwRect &rOld,
             pFly->NotifyBackground( pOld, aTmp, PREP_FLY_CHGD );
         }
     }
-    else if ( pOldPrt && *pOldPrt != pFly->getFramePrintArea() &&
-              pFly->GetFormat()->GetSurround().IsContour() )
+    else if(pOldPrt && *pOldPrt != pFly->getFramePrintArea())
     {
-        // #i24097#
-        pFly->NotifyBackground( pFly->FindPageFrame(), aFrame, PREP_FLY_ARRIVE );
+        bool bNotifyBackground(pFly->GetFormat()->GetSurround().IsContour());
+
+        if(!bNotifyBackground &&
+            pFly->IsFlyFreeFrame() &&
+            static_cast< const SwFlyFreeFrame* >(pFly)->supportsAutoContour())
+        {
+            // RotateFlyFrame3: Also notify for FlyFrames which allow AutoContour
+            bNotifyBackground = true;
+        }
+
+        if(bNotifyBackground)
+        {
+            // #i24097#
+            pFly->NotifyBackground( pFly->FindPageFrame(), aFrame, PREP_FLY_ARRIVE );
+        }
     }
 }
 
diff --git a/sw/source/core/text/txtfly.cxx b/sw/source/core/text/txtfly.cxx
index fff55186d725..2fb5c47a38a4 100644
--- a/sw/source/core/text/txtfly.cxx
+++ b/sw/source/core/text/txtfly.cxx
@@ -177,7 +177,22 @@ const SwRect SwContourCache::CalcBoundRect( const SwAnchoredObject* pAnchoredObj
 {
     SwRect aRet;
     const SwFrameFormat* pFormat = &(pAnchoredObj->GetFrameFormat());
-    if( pFormat->GetSurround().IsContour() &&
+    bool bHandleContour(pFormat->GetSurround().IsContour());
+
+    if(!bHandleContour)
+    {
+        // RotateFlyFrame3: Object has no set contour, but for rotated
+        // FlyFrames we can create a 'default' contour to make text
+        // flow around the free, non-covered
+        const SwFlyFreeFrame* pSwFlyFreeFrame(dynamic_cast< const SwFlyFreeFrame* >(pAnchoredObj));
+
+        if(nullptr != pSwFlyFreeFrame && pSwFlyFreeFrame->supportsAutoContour())
+        {
+            bHandleContour = true;
+        }
+    }
+
+    if( bHandleContour &&
         ( dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) ==  nullptr ||
           ( static_cast<const SwFlyFrame*>(pAnchoredObj)->Lower() &&
             static_cast<const SwFlyFrame*>(pAnchoredObj)->Lower()->IsNoTextFrame() ) ) )
commit 059469926e359153b9b291790ef2df84fa63fda9
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Nov 16 12:54:21 2017 +0100

    RotateFlyFrame3: Corrected Contour when rotated
    
    When rotated, the contour has to be adapted to that state
    and also needs to be calculated in untransformed state,
    added needed code. Also need to add a ClipRegion set at
    the target OutputDevice (e.g. from Contour) to the prepared
    GraphicPrimitive. It was sometimes used due to a VCL_Based
    PrimitiveRenderer being used, but that is just a coincidence.
    
    Change-Id: I1888ecd0468243bf2f41233b0cb3f99a50ac9805

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 9432576bdcf4..93103489af70 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -78,6 +78,7 @@
 #include <txtfly.hxx>
 #include <vcl/graphicfilter.hxx>
 #include <vcl/pdfextoutdevdata.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
 
 using namespace com::sun::star;
 
@@ -348,10 +349,15 @@ void SwNoTextFrame::GetGrfArea( SwRect &rRect, SwRect* pOrigRect ) const
 {
     // Currently only used for scaling, cropping and mirroring the contour of graphics!
     // Everything else is handled by GraphicObject
-
     // We put the graphic's visible rectangle into rRect.
     // pOrigRect contains position and size of the whole graphic.
 
+    // RotateFlyFrame3: SwFrame may be transformed. Get untransformed
+    // SwRect(s) as base of calculation
+    const TransformableSwFrame* pTransformableSwFrame(getTransformableSwFrame());
+    const SwRect aFrameArea(pTransformableSwFrame ? pTransformableSwFrame->getUntransformedFrameArea() : getFrameArea());
+    const SwRect aFramePrintArea(pTransformableSwFrame ? pTransformableSwFrame->getUntransformedFramePrintArea() : getFramePrintArea());
+
     const SwAttrSet& rAttrSet = GetNode()->GetSwAttrSet();
     const SwCropGrf& rCrop = rAttrSet.GetCropGrf();
     MirrorGraph nMirror = rAttrSet.GetMirrorGrf().GetValue();
@@ -376,7 +382,7 @@ void SwNoTextFrame::GetGrfArea( SwRect &rRect, SwRect* pOrigRect ) const
     Size aOrigSz( static_cast<const SwNoTextNode*>(GetNode())->GetTwipSize() );
     if ( !aOrigSz.Width() )
     {
-        aOrigSz.Width() = getFramePrintArea().Width();
+        aOrigSz.Width() = aFramePrintArea.Width();
         nLeftCrop  = -rCrop.GetLeft();
         nRightCrop = -rCrop.GetRight();
     }
@@ -384,7 +390,7 @@ void SwNoTextFrame::GetGrfArea( SwRect &rRect, SwRect* pOrigRect ) const
     {
         nLeftCrop = std::max( aOrigSz.Width() -
                             (rCrop.GetRight() + rCrop.GetLeft()), long(1) );
-        const double nScale = double(getFramePrintArea().Width())  / double(nLeftCrop);
+        const double nScale = double(aFramePrintArea.Width())  / double(nLeftCrop);
         nLeftCrop  = long(nScale * -rCrop.GetLeft() );
         nRightCrop = long(nScale * -rCrop.GetRight() );
     }
@@ -399,14 +405,14 @@ void SwNoTextFrame::GetGrfArea( SwRect &rRect, SwRect* pOrigRect ) const
 
     if( !aOrigSz.Height() )
     {
-        aOrigSz.Height() = getFramePrintArea().Height();
+        aOrigSz.Height() = aFramePrintArea.Height();
         nTopCrop   = -rCrop.GetTop();
         nBottomCrop= -rCrop.GetBottom();
     }
     else
     {
         nTopCrop = std::max( aOrigSz.Height() - (rCrop.GetTop() + rCrop.GetBottom()), long(1) );
-        const double nScale = double(getFramePrintArea().Height()) / double(nTopCrop);
+        const double nScale = double(aFramePrintArea.Height()) / double(nTopCrop);
         nTopCrop   = long(nScale * -rCrop.GetTop() );
         nBottomCrop= long(nScale * -rCrop.GetBottom() );
     }
@@ -419,9 +425,9 @@ void SwNoTextFrame::GetGrfArea( SwRect &rRect, SwRect* pOrigRect ) const
         nBottomCrop= nTmpCrop;
     }
 
-    Size  aVisSz( getFramePrintArea().SSize() );
+    Size  aVisSz( aFramePrintArea.SSize() );
     Size  aGrfSz( aVisSz );
-    Point aVisPt( getFrameArea().Pos() + getFramePrintArea().Pos() );
+    Point aVisPt( aFrameArea.Pos() + aFramePrintArea.Pos() );
     Point aGrfPt( aVisPt );
 
     // Set the "visible" rectangle first
@@ -999,6 +1005,28 @@ void paintGraphicUsingPrimitivesHelper(
             rGraphicTransform,
             rGrfObj,
             rGraphicAttr);
+
+        // RotateFlyFrame3: If ClipRegion is set at OutputDevice, we
+        // need to use that. Usually the renderer would be a VCL-based
+        // PrimitiveRenderer, but there are system-specific shortcuts that
+        // will *not* use the VCL-Paint of Bitmap and thus ignore this.
+        // Anyways, indirectly using a CLipRegion set at the taget OutDev
+        // when using a PrimitiveRenderer is a non-valid implication.
+        // First tried only to use when HasPolyPolygonOrB2DPolyPolygon(),
+        // but there is an optimization at ClipRegion creation that detects
+        // a single Rectangle in a tools::PolyPolygon and forces to a simple
+        // RegionBand-based implementation, so cannot use it here.
+        if(rOutputDevice.IsClipRegion())
+        {
+            const basegfx::B2DPolyPolygon aClip(rOutputDevice.GetClipRegion().GetAsB2DPolyPolygon());
+
+            if(0 != aClip.count())
+            {
+                aContent[0] = new drawinglayer::primitive2d::MaskPrimitive2D(
+                    aClip,
+                    aContent);
+            }
+        }
     }
 
     basegfx::B2DRange aTargetRange(0.0, 0.0, 1.0, 1.0);
commit d74b26b41bfea3ba7a1834953b2bfe9b7ff0d70f
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Wed Nov 15 13:56:38 2017 +0100

    RotateFlyFrame3: Corrected interactive Crop
    
    To correct interactive Crop in transformed states, I had to
    rework some stuff involved that anyways was in a non optimal
    state. Added functionality to translate the object to make
    Crop seem to work more seamlessly. Some mapping was needed
    to make the Cropped, transformed object to be in the correct
    relative position to the uncropped, untransfomed one.
    Restructured TransformableSwFrame to directly re-create
    last non-transformed SwFrame(s) from the SwFrameAreaDefinition
    from the current Transformations, offering the untransformed
    SwRect(s) now for usage.
    Identified and corrected error when FlyFrame was translated
    using keyboard, the accessing method needed to adapt position
    in the transformed case.
    Started to look at Contour stuff, adapted a set contour to be
    correctly used by adapting it as needed in the transformed case.
    
    Change-Id: I0d5f14958bcd6f826b9abd53f1f47b7d0bc5a0e2

diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx
index 2a7c629a05d3..bf227c9635c4 100644
--- a/include/svx/svdobj.hxx
+++ b/include/svx/svdobj.hxx
@@ -75,10 +75,9 @@ class OutputDevice;
 class Fraction;
 
 namespace basegfx {
-
+class B2DPoint;
 class B2DPolyPolygon;
 class B2DHomMatrix;
-
 }
 
 namespace sdr
@@ -511,14 +510,14 @@ public:
     /// Nbc means "no broadcast".
     virtual void NbcMove  (const Size& rSiz);
     virtual void NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact);
-    virtual void NbcCrop  (const Point& rRef, const Fraction& xFact, const Fraction& yFact);
+    virtual void NbcCrop  (const basegfx::B2DPoint& rRef, double fxFact, double fyFact);
     virtual void NbcRotate(const Point& rRef, long nAngle, double sn, double cs);
     virtual void NbcMirror(const Point& rRef1, const Point& rRef2);
     virtual void NbcShear (const Point& rRef, long nAngle, double tn, bool bVShear);
 
     virtual void Move  (const Size& rSiz);
     virtual void Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative = true);
-    virtual void Crop  (const Point& rRef, const Fraction& xFact, const Fraction& yFact);
+    virtual void Crop  (const basegfx::B2DPoint& rRef, double fxFact, double fyFact);
     virtual void Rotate(const Point& rRef, long nAngle, double sn, double cs);
     virtual void Mirror(const Point& rRef1, const Point& rRef2);
     virtual void Shear (const Point& rRef, long nAngle, double tn, bool bVShear);
diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index 714d4e66a334..1e3344c26410 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -3766,25 +3766,17 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
 
     if(bExternal)
     {
-        // With Ref point (opposed to dragged point), X scale and Y scale,
+        // With aLocalStart point (opposed to dragged point), X scale and Y scale,
         // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj
-        // crop. aRef needs to be adapted to concrete Object's boundaries which
-        // is different from Crop-Ranges. This is because the Graphic and it's
-        // SdrObject representation is inside the FlyFrame, but not identical
-        // with it.
-        const tools::Rectangle& rOutRect(pExternalSdrObject->GetCurrentBoundRect());
-        const basegfx::B2DHomMatrix aExternalTransform(
-            basegfx::utils::createScaleTranslateB2DHomMatrix(
-                rOutRect.getWidth(), rOutRect.getHeight(),
-                rOutRect.Left(), rOutRect.Top()));
-        const basegfx::B2DPoint aRef(aExternalTransform * aLocalStart);
+        // crop. Use aLocalStart unchanged, so being relative to the Crop-Action,
+        // the called instance knows best how to use it
         const double fScaleX(aRangeNewNoShearNoRotate.getWidth() / aRangeOriginalNoShearNoRotate.getWidth());
         const double fScaleY(aRangeNewNoShearNoRotate.getHeight() / aRangeOriginalNoShearNoRotate.getHeight());
 
         pExternalSdrObject->Crop(
-            Point(basegfx::fround(aRef.getX()), basegfx::fround(aRef.getY())),
-            Fraction(fScaleX),
-            Fraction(fScaleY));
+            aLocalStart,
+            fScaleX,
+            fScaleY);
     }
     else
     {
diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx
index d5ef63b3c842..020c75655be8 100644
--- a/svx/source/svdraw/svdobj.cxx
+++ b/svx/source/svdraw/svdobj.cxx
@@ -1485,8 +1485,10 @@ void SdrObject::Move(const Size& rSiz)
     }
 }
 
-void SdrObject::NbcCrop(const Point& /*rRef*/, const Fraction& /*xFact*/, const Fraction& /*yFact*/) {
-    // Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrGrafObj
+void SdrObject::NbcCrop(const basegfx::B2DPoint& /*aRef*/, double /*fxFact*/, double /*fyFact*/)
+{
+    // Default: does nothing. Real behaviour in SwVirtFlyDrawObj and SdrDragCrop::EndSdrDrag.
+    // Where SwVirtFlyDrawObj is the only real user of it to do something local
 }
 
 void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction& yFact, bool bUnsetRelative)
@@ -1507,10 +1509,10 @@ void SdrObject::Resize(const Point& rRef, const Fraction& xFact, const Fraction&
     }
 }
 
-void SdrObject::Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+void SdrObject::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
 {
     tools::Rectangle aBoundRect0; if (pUserCall!=nullptr) aBoundRect0=GetLastBoundRect();
-    NbcCrop(rRef, xFact, yFact);
+    NbcCrop(rRef, fxFact, fyFact);
     SetChanged();
     BroadcastObjectChange();
     SendUserCall(SdrUserCallType::Resize,aBoundRect0);
diff --git a/svx/source/uitest/sdrobject.cxx b/svx/source/uitest/sdrobject.cxx
index f70cb2e3c511..4fdd4c315764 100644
--- a/svx/source/uitest/sdrobject.cxx
+++ b/svx/source/uitest/sdrobject.cxx
@@ -99,6 +99,8 @@ void SdrUIObject::execute(const OUString& rAction,
     }
     else if (rAction == "CROP")
     {
+        // RotateFlyFrame3: Note: Crop does nothing at SdrObject
+        // anymore, see comment at SdrObject::NbcCrop
         auto itrNX = rParameters.find("X");
         if (itrNX == rParameters.end())
             throw css::uno::RuntimeException("missing parameter X");
@@ -107,23 +109,21 @@ void SdrUIObject::execute(const OUString& rAction,
         if (itrNY == rParameters.end())
             throw css::uno::RuntimeException("missing parameter Y");
 
-        long nX = itrNX->second.toInt32();
-        long nY = itrNY->second.toInt32();
-        Point aPos(nX, nY);
+        const double fX(itrNX->second.toDouble());
+        const double fY(itrNY->second.toDouble());
+        const basegfx::B2DPoint aPos(fX, fY);
 
         auto itrFracX = rParameters.find("FRAC_X");
         if (itrFracX == rParameters.end())
             throw css::uno::RuntimeException("missing parameter FRAC_X");
-        double nFracX = itrFracX->second.toDouble();
-        Fraction aFracX(nFracX);
+        const double fFracX(itrFracX->second.toDouble());
 
         auto itrFracY = rParameters.find("FRAC_Y");
         if (itrFracY == rParameters.end())
             throw css::uno::RuntimeException("missing parameter FRAC_Y");
-        double nFracY = itrFracY->second.toDouble();
-        Fraction aFracY(nFracY);
+        const double fFracY(itrFracY->second.toDouble());
 
-        pObj->Crop(aPos, aFracX, aFracY);
+        pObj->Crop(aPos, fFracX, fFracY);
     }
     else if (rAction == "ROTATE")
     {
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index e1035a3754fa..a4466f1f9085 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -634,9 +634,9 @@ void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
 {
     if(GetFlyFrame()->IsFlyFreeFrame() && static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame())
     {
-        // When we have a change in transformed state, we need to fall back to the
-        // state without possible transformations. Restore FrameArea and use aOutRect
-        // from old FrameArea. From here, all former actions below should be fine
+        // When we have a change and are in transformed state (e.g. rotation used),
+        // we need to fall back to the un-transformed state to keep the old code below
+        // working properly. Restore FrameArea and use aOutRect from old FrameArea.
         TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
         pTransformableSwFrame->restoreFrameAreas();
         aOutRect = GetFlyFrame()->getFrameArea().SVRect();
@@ -788,7 +788,7 @@ void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
 }
 
 
-void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+void SwVirtFlyDrawObj::NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
 {
     // Get Wrt Shell
     SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() );
@@ -805,50 +805,65 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
         return;
     }
 
+    // Get graphic object size in 100th of mm
+    const MapMode aMapMode100thmm(MapUnit::Map100thMM);
+    Size aGraphicSize(pGraphicObject->GetPrefSize());
+
+    if( MapUnit::MapPixel == pGraphicObject->GetPrefMapMode().GetMapUnit() )
+    {
+        aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
+    }
+    else
+    {
+        aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, pGraphicObject->GetPrefMapMode(), aMapMode100thmm);
+    }
+
+    if( aGraphicSize.Width() == 0 || aGraphicSize.Height() == 0 )
+    {
+        return ;
+    }
+
     const bool bIsTransformableSwFrame(
         GetFlyFrame()->IsFlyFreeFrame() &&
         static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
 
     if(bIsTransformableSwFrame)
     {
-        // When we have a change in transformed state, we need to fall back to the
-        // state without possible transformations. Restore FrameArea and use aOutRect
-        // from old FrameArea. From here, all former actions below should be fine
+        // When we have a change and are in transformed state (e.g. rotation used),
+        // we need to fall back to the un-transformed state to keep the old code below
+        // working properly. Restore FrameArea and use aOutRect from old FrameArea.
         TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
         pTransformableSwFrame->restoreFrameAreas();
         aOutRect = GetFlyFrame()->getFrameArea().SVRect();
     }
 
     // Compute old and new rect. This will give us the deformation to apply to
-    // the object to crop
-    const long nOldWidth(aOutRect.GetWidth());
-    const long nOldHeight(aOutRect.GetHeight());
+    // the object to crop. OldRect is the inner frame, see getFullDragClone()
+    // below where getFramePrintAreaTransformation is used as object geometry for Crop
+    const tools::Rectangle aOldRect(
+        GetFlyFrame()->getFrameArea().TopLeft() + GetFlyFrame()->getFramePrintArea().TopLeft(),
+        GetFlyFrame()->getFramePrintArea().SSize());
+    const long nOldWidth(aOldRect.GetWidth());
+    const long nOldHeight(aOldRect.GetHeight());
 
     if (!nOldWidth || !nOldHeight)
     {
         return;
     }
 
-    tools::Rectangle aNewRect( aOutRect );
-    ResizeRect( aNewRect, rRef, xFact, yFact );
-
-    // Get graphic object size in 100th of mm
-    const MapMode aMapMode100thmm(MapUnit::Map100thMM);
-    Size aGraphicSize(pGraphicObject->GetPrefSize());
-
-    if( MapUnit::MapPixel == pGraphicObject->GetPrefMapMode().GetMapUnit() )
-    {
-        aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
-    }
-    else
-    {
-        aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, pGraphicObject->GetPrefMapMode(), aMapMode100thmm);
-    }
+    // rRef is relative to the Crop-Action, si in X/Y-Ranges of [0.0 .. 1.0],
+    // to get the correct absolute position, transform using the old Rect
+    const Point aRef(
+        aOldRect.Left() + basegfx::fround(aOldRect.GetWidth() * rRef.getX()),
+        aOldRect.Top() + basegfx::fround(aOldRect.GetHeight() * rRef.getY()));
 
-    if( aGraphicSize.Width() == 0 || aGraphicSize.Height() == 0 )
-    {
-        return ;
-    }
+    // appy transformation, use old ResizeRect for now
+    tools::Rectangle aNewRect( aOldRect );
+    ResizeRect(
+        aNewRect,
+        aRef,
+        Fraction(fxFact),
+        Fraction(fyFact));
 
     // Get old values for crop in 10th of mm
     SfxItemSet aSet( pSh->GetAttrPool(), svl::Items<RES_GRFATR_CROPGRF, RES_GRFATR_CROPGRF>{} );
@@ -865,10 +880,10 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
     double fScaleX = ( aGraphicSize.Width() - aCropRectangle.Left() - aCropRectangle.Right() ) / (double)nOldWidth;
     double fScaleY = ( aGraphicSize.Height() - aCropRectangle.Top() - aCropRectangle.Bottom() ) / (double)nOldHeight;
 
-    sal_Int32 nDiffLeft = aNewRect.Left() - aOutRect.Left();
-    sal_Int32 nDiffTop = aNewRect.Top() - aOutRect.Top();
-    sal_Int32 nDiffRight = aNewRect.Right() - aOutRect.Right();
-    sal_Int32 nDiffBottom = aNewRect.Bottom() - aOutRect.Bottom();
+    sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
+    sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
+    sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
+    sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
 
     // Compute new values in 10th of mm
     sal_Int32 nLeftCrop = static_cast<sal_Int32>( aCropRectangle.Left() + nDiffLeft * fScaleX );
@@ -878,7 +893,7 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
 
     // Apply values
     pSh->StartAllAction();
-//    pSh->StartUndo(SwUndoId::START);
+    // pSh->StartUndo(SwUndoId::START);
 
     // Set new crop values in twips
     aCrop.SetLeft  (convertMm100ToTwip(nLeftCrop));
@@ -890,15 +905,21 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
     // Set new frame size
     SwFrameFormat *pFormat = GetFormat();
     SwFormatFrameSize aSz( pFormat->GetFrameSize() );
-    aSz.SetWidth(aNewRect.GetWidth());
-    aSz.SetHeight(aNewRect.GetHeight());
+    const long aNewWidth(aNewRect.GetWidth() + (aOutRect.GetWidth() - aOldRect.GetWidth()));
+    const long aNewHeight(aNewRect.GetHeight() + (aOutRect.GetHeight() - aOldRect.GetHeight()));
+    aSz.SetWidth(aNewWidth);
+    aSz.SetHeight(aNewHeight);
     pFormat->GetDoc()->SetAttr( aSz, *pFormat );
 
+    // add move - to make result look better. Fill with defaults
+    // for the untransformed case
+    Point aNewTopLeft(aNewRect.TopLeft());
+    const Point aOldTopLeft(aOldRect.TopLeft());
+
     if(bIsTransformableSwFrame)
     {
-        // Need to correct the TopLeft position in rotated state to make
-        // the interaction look correct. First, extract rotation (and others
-        // currently not used)
+        // Need to correct the NewTopLeft position in transformed state to make
+        // the interaction look correct. First, extract rotation
         basegfx::B2DVector aScale, aTranslate;
         double fRotate, fShearX;
         GetFlyFrame()->getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
@@ -922,22 +943,22 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
 
         // Create the new TopLeft of the unrotated, cropped object by creating
         // as if re-rceating the unrotated geometry
-        const Point aNewTopLeft(
+        aNewTopLeft = Point(
             basegfx::fround(aRotNewCenter.getX() - (0.5 * aNewRect.getWidth())),
             basegfx::fround(aRotNewCenter.getY() - (0.5 * aNewRect.getHeight())));
+    }
 
-        // checvk if we have movement and execute if yes
-        const Size aDeltaMove(
-            basegfx::fround(aNewTopLeft.getX() - aOutRect.Left()),
-            basegfx::fround(aNewTopLeft.getY() - aOutRect.Top()));
+    // check if we have movement and execute if yes
+    const Size aDeltaMove(
+        aNewTopLeft.X() - aOldTopLeft.X(),
+        aNewTopLeft.Y() - aOldTopLeft.Y());
 
-        if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
-        {
-            NbcMove(aDeltaMove);
-        }
+    if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
+    {
+        NbcMove(aDeltaMove);
     }
 
-//    pSh->EndUndo(SwUndoId::END);
+    // pSh->EndUndo(SwUndoId::END);
     pSh->EndAllAction();
 }
 
@@ -979,13 +1000,14 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef, const Fraction& xFact, const
         basegfx::B2DVector aScale, aTranslate;
         double fRotate, fShearX;
         aNewMat.decompose(aScale, aTranslate, fRotate, fShearX);
+        const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
 
-        // create new modified OutRect
+        // create new modified, but untransformed OutRect
         aOutRect = tools::Rectangle(
-            basegfx::fround(aCenter.getX() - (0.5 * aScale.getX())),
-            basegfx::fround(aCenter.getY() - (0.5 * aScale.getY())),
-            basegfx::fround(aCenter.getX() + (0.5 * aScale.getX())),
-            basegfx::fround(aCenter.getY() + (0.5 * aScale.getY())));
+            basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
+            basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
+            basegfx::fround(aCenter.getX() + (0.5 * aAbsScale.getX())),
+            basegfx::fround(aCenter.getY() + (0.5 * aAbsScale.getY())));
 
         // restore FrameAreas so that actions below not adapted to new
         // full transformations take the correct actions
@@ -1115,9 +1137,9 @@ void SwVirtFlyDrawObj::Resize(const Point& rRef,
     GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
 }
 
-void SwVirtFlyDrawObj::Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
+void SwVirtFlyDrawObj::Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact)
 {
-    NbcCrop( rRef, xFact, yFact );
+    NbcCrop( rRef, fxFact, fyFact );
     SetChanged();
     GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
 }
diff --git a/sw/source/core/frmedt/fefly1.cxx b/sw/source/core/frmedt/fefly1.cxx
index f36eac32c09c..105689dbf848 100644
--- a/sw/source/core/frmedt/fefly1.cxx
+++ b/sw/source/core/frmedt/fefly1.cxx
@@ -368,7 +368,24 @@ void SwFEShell::SetFlyPos( const Point& rAbsPos )
     // Set an anchor starting from the absolute position for paragraph bound Flys
     // Anchor and new RelPos will be calculated and set by the Fly
     if ( pFly->IsFlyAtContentFrame() )
-        static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos( rAbsPos );
+    {
+        if(pFly->IsFlyFreeFrame() && static_cast<SwFlyFreeFrame*>(pFly)->isTransformableSwFrame())
+        {
+            // RotateFlyFrame3: When we have a change and are in transformed state (e.g. rotation used),
+            // we need to correct the absolute position (rAbsPos) which was created in
+            // transformed coordinates to untransformed state
+            TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(pFly)->getTransformableSwFrame());
+            const SwRect aUntransformedFrameArea(pTransformableSwFrame->getUntransformedFrameArea());
+            const Point aNewAbsPos(
+                rAbsPos.X() + aUntransformedFrameArea.Left() - pFly->getFrameArea().Left(),
+                rAbsPos.Y() + aUntransformedFrameArea.Top() - pFly->getFrameArea().Top());
+            static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos(aNewAbsPos);
+        }
+        else
+        {
+            static_cast<SwFlyAtContentFrame*>(pFly)->SetAbsPos( rAbsPos );
+        }
+    }
     else
     {
             const SwFrame *pAnch = pFly->GetAnchorFrame();
diff --git a/sw/source/core/inc/dflyobj.hxx b/sw/source/core/inc/dflyobj.hxx
index e2fcac536073..77df7060420d 100644
--- a/sw/source/core/inc/dflyobj.hxx
+++ b/sw/source/core/inc/dflyobj.hxx
@@ -101,11 +101,11 @@ public:
     virtual       void       NbcMove  (const Size& rSiz) override;
     virtual       void       NbcResize(const Point& rRef, const Fraction& xFact,
                                        const Fraction& yFact) override;
-    virtual       void       NbcCrop(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override;
+    virtual       void       NbcCrop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact) override;
     virtual       void       Move  (const Size& rSiz) override;
     virtual       void       Resize(const Point& rRef, const Fraction& xFact,
                                     const Fraction& yFact, bool bUnsetRelative = true) override;
-    virtual       void       Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override;
+    virtual       void       Crop(const basegfx::B2DPoint& rRef, double fxFact, double fyFact) override;
     virtual       void       addCropHandles(SdrHdlList& rTarget) const override;
     virtual       void       Rotate(const Point& rRef, long nAngle, double sn, double cs) override;
 
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index 5334a0269447..eaae5b89059d 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -25,6 +25,7 @@
 
 // #i28701#
 class SwFlyAtContentFrame;
+class SwNoTextFrame;
 
 double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
 
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 811bd390d82d..cc455a995008 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -146,6 +146,7 @@ protected:
 
 public:
     SwFrameAreaDefinition();
+    virtual ~SwFrameAreaDefinition();
 
     // read access to mb*Valid flags
     bool isFrameAreaPositionValid() const { return mbFrameAreaPositionValid; }
@@ -212,8 +213,8 @@ public:
 };
 
 /// RotateFlyFrame3: Helper class when you want to make your SwFrame derivate
-/// transformable. It provides some tooling to do so. To use,
-/// derive your SwFrame from it
+/// transformable. It provides some tooling to do so. To use, add as member
+/// (see e.g. SwFlyFreeFrame which uses 'std::unique_ptr< TransformableSwFrame >')
 class SW_DLLPUBLIC TransformableSwFrame
 {
 private:
@@ -221,54 +222,50 @@ private:
     SwFrameAreaDefinition&  mrSwFrameAreaDefinition;
 
     // FrameAreaTransformation and FramePrintAreaTransformation
-    // here when more than translate/scale is used (e.g. rotation)
+    // !identtity when needed (translate/scale is used (e.g. rotation))
     basegfx::B2DHomMatrix   maFrameAreaTransformation;
     basegfx::B2DHomMatrix   maFramePrintAreaTransformation;
 
-    // last saved versions of SwRect(s) from SwFrameAreaDefinition,
-    // set from adaptFrameAreasToTransformations before modifying
-    // SwFrameAreaDefinition(s), used for restore from
-    // restoreFrameAreas
-    SwRect                  maSavedFrameArea;
-    SwRect                  maSavedFramePrintArea;
-
 public:
     TransformableSwFrame(SwFrameAreaDefinition& rSwFrameAreaDefinition)
     :   mrSwFrameAreaDefinition(rSwFrameAreaDefinition),
         maFrameAreaTransformation(),
-        maFramePrintAreaTransformation(),
-        maSavedFrameArea(),
-        maSavedFramePrintArea()
+        maFramePrintAreaTransformation()
     {
     }
 
-    // Support for Transformations for inner frame of a SwGrfNode
+    // get SwFrameArea in transformation form
     const basegfx::B2DHomMatrix& getLocalFrameAreaTransformation() const
     {
         return maFrameAreaTransformation;
     }
 
+    // get SwFramePrintArea in transformation form
     const basegfx::B2DHomMatrix& getLocalFramePrintAreaTransformation() const
     {
         return maFramePrintAreaTransformation;
     }
 
+    // Helpers to re-create the untransformed SwRect(s) originally
+    // in the SwFrameAreaDefinition, based on the current Transformations.
+    SwRect getUntransformedFrameArea() const;
+    SwRect getUntransformedFramePrintArea() const;
+
     // Helper method to re-create FrameAreaTransformations based on the
-    // curent FrameAreaDefinition, given rotation and Center
+    // curent FrameAreaDefinition transformed by given rotation and Center
     void createFrameAreaTransformations(
         double fRotation,
         const basegfx::B2DPoint& rCenter);
 
     // Tooling method to reset the SwRect(s) in the current
     // SwFrameAreaDefinition which are already apapted to
-    // Transformation back to the untransformed state that was
-    // last saved (see adaptFrameAreasToTransformations).
+    // Transformation back to the untransformed state, using
+    // the getUntransformedFrame*Area calls above when needed.
     // Only the SwRect(s) are changed back, not the transformations.
     void restoreFrameAreas();
 
     // Re-Creates the SwRect(s) as BoundAreas based on the current
-    // set Transformations, also saves the last SwRect(s) to the save
-    // values.
+    // set Transformations.
     void adaptFrameAreasToTransformations();
 
     // Modify current definitions by applying the given transformation
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index 684b989d76b8..5163fbb3f3c4 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -62,6 +62,8 @@
 #include <IDocumentLayoutAccess.hxx>
 #include <textboxhelper.hxx>
 #include <txtfly.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
 
 using namespace ::com::sun::star;
 
@@ -2431,8 +2433,9 @@ bool SwFlyFrame::GetContour( tools::PolyPolygon&   rContour,
 {
     vcl::RenderContext* pRenderContext = getRootFrame()->GetCurrShell()->GetOut();
     bool bRet = false;
-    if( GetFormat()->GetSurround().IsContour() && Lower() &&
-        Lower()->IsNoTextFrame() )
+    const bool bIsCandidate(Lower() && Lower()->IsNoTextFrame());
+
+    if(bIsCandidate && GetFormat()->GetSurround().IsContour())
     {
         SwNoTextNode *pNd = const_cast<SwNoTextNode*>(static_cast<const SwNoTextNode*>(static_cast<const SwContentFrame*>(Lower())->GetNode()));
         // OD 16.04.2003 #i13147# - determine <GraphicObject> instead of <Graphic>
@@ -2524,6 +2527,31 @@ bool SwFlyFrame::GetContour( tools::PolyPolygon&   rContour,
             bRet = true;
         }
     }
+
+    if(bRet &&
+        rContour.Count() &&
+        IsFlyFreeFrame() &&
+        static_cast<const SwFlyFreeFrame*>(this)->isTransformableSwFrame())
+    {
+        // RotateFlyFrame: Need to adapt contour to transformation
+        basegfx::B2DVector aScale, aTranslate;
+        double fRotate, fShearX;
+        getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+        if(!basegfx::fTools::equalZero(fRotate))
+        {
+            basegfx::B2DPolyPolygon aSource(rContour.getB2DPolyPolygon());
+            const basegfx::B2DPoint aCenter(getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
+            const basegfx::B2DHomMatrix aRotateAroundCenter(
+                basegfx::utils::createRotateAroundPoint(
+                    aCenter.getX(),
+                    aCenter.getY(),
+                    fRotate));
+            aSource.transform(aRotateAroundCenter);
+            rContour = tools::PolyPolygon(aSource);
+        }
+    }
+
     return bRet;
 }
 
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 7f7068ed0362..08debf8408e2 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -65,6 +65,10 @@ SwFrameAreaDefinition::SwFrameAreaDefinition()
 {
 }
 
+SwFrameAreaDefinition::~SwFrameAreaDefinition()
+{
+}
+
 void SwFrameAreaDefinition::setFrameAreaPositionValid(bool bNew)
 {
     if(mbFrameAreaPositionValid != bNew)
@@ -146,6 +150,55 @@ void SwFrameAreaDefinition::transform_translate(const Point& rOffset)
     }
 }
 
+SwRect TransformableSwFrame::getUntransformedFrameArea() const
+{
+    const basegfx::B2DHomMatrix& rSource(getLocalFrameAreaTransformation());
+
+    if(rSource.isIdentity())
+    {
+        return mrSwFrameAreaDefinition.getFrameArea();
+    }
+    else
+    {
+        basegfx::B2DVector aScale, aTranslate;
+        double fRotate, fShearX;
+        rSource.decompose(aScale, aTranslate, fRotate, fShearX);
+        const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
+        const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
+
+        return SwRect(
+            basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())),
+            basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())),
+            basegfx::fround(aAbsScale.getX()),
+            basegfx::fround(aAbsScale.getY()));
+    }
+}
+
+SwRect TransformableSwFrame::getUntransformedFramePrintArea() const
+{
+    const basegfx::B2DHomMatrix& rSource(getLocalFramePrintAreaTransformation());
+
+    if(rSource.isIdentity())
+    {
+        return mrSwFrameAreaDefinition.getFramePrintArea();
+    }
+    else
+    {
+        basegfx::B2DVector aScale, aTranslate;
+        double fRotate, fShearX;
+        rSource.decompose(aScale, aTranslate, fRotate, fShearX);
+        const basegfx::B2DPoint aCenter(rSource * basegfx::B2DPoint(0.5, 0.5));
+        const basegfx::B2DVector aAbsScale(basegfx::absolute(aScale));
+        const SwRect aUntransformedFrameArea(getUntransformedFrameArea());
+
+        return SwRect(
+            basegfx::fround(aCenter.getX() - (0.5 * aAbsScale.getX())) - aUntransformedFrameArea.Left(),
+            basegfx::fround(aCenter.getY() - (0.5 * aAbsScale.getY())) - aUntransformedFrameArea.Top(),
+            basegfx::fround(aAbsScale.getX()),
+            basegfx::fround(aAbsScale.getY()));
+    }
+}
+
 void TransformableSwFrame::createFrameAreaTransformations(
     double fRotation,
     const basegfx::B2DPoint& rCenter)
@@ -178,7 +231,6 @@ void TransformableSwFrame::adaptFrameAreasToTransformations()
 
         if(aNewFrm != mrSwFrameAreaDefinition.getFrameArea())
         {
-            maSavedFrameArea = mrSwFrameAreaDefinition.getFrameArea();
             SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
             aFrm.setSwRect(aNewFrm);
         }
@@ -196,7 +248,6 @@ void TransformableSwFrame::adaptFrameAreasToTransformations()
 
         if(aNewPrt != mrSwFrameAreaDefinition.getFramePrintArea())
         {
-            maSavedFramePrintArea = mrSwFrameAreaDefinition.getFramePrintArea();
             SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
             aPrt.setSwRect(aNewPrt);
         }
@@ -206,20 +257,17 @@ void TransformableSwFrame::adaptFrameAreasToTransformations()
 void TransformableSwFrame::restoreFrameAreas()
 {
     // This can be done fully based on the Transformations currently
-    // set (and I did this in the beginning and it may be necessary
-    // again later), but for simplicity and performance now done using
-    // the last save values for the SwRect(s), see above
-
-    if(!getLocalFrameAreaTransformation().isIdentity() && maSavedFrameArea != mrSwFrameAreaDefinition.getFrameArea())
+    // set, so use this. Only needed when transformation *is* used
+    if(!getLocalFrameAreaTransformation().isIdentity())
     {
         SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
-        aFrm.setSwRect(maSavedFrameArea);
+        aFrm.setSwRect(getUntransformedFrameArea());
     }
 
-    if(!getLocalFramePrintAreaTransformation().isIdentity() && maSavedFramePrintArea != mrSwFrameAreaDefinition.getFramePrintArea())
+    if(!getLocalFramePrintAreaTransformation().isIdentity())
     {
         SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
-        aPrt.setSwRect(maSavedFramePrintArea);
+        aPrt.setSwRect(getUntransformedFramePrintArea());
     }
 }
 
commit 1059e234f4b3b3f6b770b2e4d973923e54e7045b
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Tue Nov 14 18:07:32 2017 +0100

    RotateFlyFrame3: Made interactions work properly
    
    Have now created working interactive Rotation, Scale, Move
    and Crop. Using as much of the old code as possible since
    it does corrections based on BorderWidth/s stuff and similar.
    To do so, need to back-transform and execute in unrotated/
    untransformed state as much as possible. Had some problems
    with SwVirtFlyDrawObj::NbcMove usages and hacks there, had
    to restructure some of these.
    
    Change-Id: Ibedf6d834f96b2f8e9c1ace2a0c984aa26cedc74

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 3971c9140da2..9432576bdcf4 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -473,7 +473,7 @@ const Size& SwNoTextFrame::GetSize() const
 void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
 {
     // RotateFlyFrame3 - inner frame. Get rotation and check if used
-    const double fRotation(getFrameRotation());
+    const double fRotation(getLocalFrameRotation());
     const bool bRotated(!basegfx::fTools::equalZero(fRotation));
 
     if(bRotated)
@@ -498,7 +498,7 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
             // is currently beyond scope
             if(pUpperFly->isTransformableSwFrame())
             {
-                pUpperFly->getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+                pUpperFly->getTransformableSwFrame()->restoreFrameAreas();
             }
         }
 
@@ -508,7 +508,7 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
         // Reset to BoundAreas will be done below automatically
         if(isTransformableSwFrame())
         {
-            getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+            getTransformableSwFrame()->restoreFrameAreas();
         }
     }
 
@@ -549,7 +549,7 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
             // upper frame, so it can bre re-created on the fly
             if(pUpperFly->isTransformableSwFrame())
             {
-                pUpperFly->getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+                pUpperFly->getTransformableSwFrame()->adaptFrameAreasToTransformations();
             }
         }
 
@@ -566,7 +566,7 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
         getTransformableSwFrame()->createFrameAreaTransformations(
             fRotation,
             aB2DCenter);
-        getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+        getTransformableSwFrame()->adaptFrameAreasToTransformations();
     }
     else
     {
@@ -615,13 +615,13 @@ void SwNoTextFrame::transform_translate(const Point& rOffset)
                 rOffset.X(), rOffset.Y()));
 
         // transform using TransformableSwFrame
-        getTransformableSwFrame()->doTransform(aTransform);
+        getTransformableSwFrame()->transform(aTransform);
     }
 }
 
 // RotateFlyFrame3 - inner frame
 // Check if we contain a SwGrfNode and get possible rotation from it
-double SwNoTextFrame::getFrameRotation() const
+double SwNoTextFrame::getLocalFrameRotation() const
 {
     const SwNoTextNode* pSwNoTextNode(nullptr != GetNode() ? GetNode()->GetNoTextNode() : nullptr);
 
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index cc12dd1baad9..e1035a3754fa 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -630,9 +630,18 @@ void SwVirtFlyDrawObj::NbcSetLogicRect(const tools::Rectangle& )
 }
 
 //  SwVirtFlyDrawObj::Move() and Resize()
-
 void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
 {
+    if(GetFlyFrame()->IsFlyFreeFrame() && static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame())
+    {
+        // When we have a change in transformed state, we need to fall back to the
+        // state without possible transformations. Restore FrameArea and use aOutRect
+        // from old FrameArea. From here, all former actions below should be fine
+        TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+        pTransformableSwFrame->restoreFrameAreas();
+        aOutRect = GetFlyFrame()->getFrameArea().SVRect();
+    }
+
     MoveRect( aOutRect, rSiz );
     const Point aOldPos( GetFlyFrame()->getFrameArea().Pos() );
     const Point aNewPos( aOutRect.TopLeft() );
@@ -649,7 +658,9 @@ void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
     //anchor must be set. Anchor and the new RelPos is calculated and
     //placed by the Fly itself.
     if( GetFlyFrame()->IsFlyAtContentFrame() )
+    {
         static_cast<SwFlyAtContentFrame*>(GetFlyFrame())->SetAbsPos( aNewPos );
+    }
     else
     {
         const SwFrameFormat *pTmpFormat = GetFormat();
@@ -781,34 +792,63 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
 {
     // Get Wrt Shell
     SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() );
+
     if (!pSh)
+    {
         return;
+    }
+
+    GraphicObject const *pGraphicObject = pSh->GetGraphicObj();
+
+    if (!pGraphicObject)
+    {
+        return;
+    }
+
+    const bool bIsTransformableSwFrame(
+        GetFlyFrame()->IsFlyFreeFrame() &&
+        static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
+
+    if(bIsTransformableSwFrame)
+    {
+        // When we have a change in transformed state, we need to fall back to the
+        // state without possible transformations. Restore FrameArea and use aOutRect
+        // from old FrameArea. From here, all former actions below should be fine
+        TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+        pTransformableSwFrame->restoreFrameAreas();
+        aOutRect = GetFlyFrame()->getFrameArea().SVRect();
+    }
 
     // Compute old and new rect. This will give us the deformation to apply to
     // the object to crop
-    tools::Rectangle aOldRect( aOutRect );
-
-    const long nOldWidth = aOldRect.GetWidth();
-    const long nOldHeight = aOldRect.GetHeight();
+    const long nOldWidth(aOutRect.GetWidth());
+    const long nOldHeight(aOutRect.GetHeight());
 
     if (!nOldWidth || !nOldHeight)
+    {
         return;
+    }
 
     tools::Rectangle aNewRect( aOutRect );
     ResizeRect( aNewRect, rRef, xFact, yFact );
 
     // Get graphic object size in 100th of mm
-    GraphicObject const *pGraphicObject = pSh->GetGraphicObj();
-    if (!pGraphicObject)
-        return;
     const MapMode aMapMode100thmm(MapUnit::Map100thMM);
     Size aGraphicSize(pGraphicObject->GetPrefSize());
+
     if( MapUnit::MapPixel == pGraphicObject->GetPrefMapMode().GetMapUnit() )
+    {
         aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
+    }
     else
+    {
         aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, pGraphicObject->GetPrefMapMode(), aMapMode100thmm);
+    }
+
     if( aGraphicSize.Width() == 0 || aGraphicSize.Height() == 0 )
+    {
         return ;
+    }
 
     // Get old values for crop in 10th of mm
     SfxItemSet aSet( pSh->GetAttrPool(), svl::Items<RES_GRFATR_CROPGRF, RES_GRFATR_CROPGRF>{} );
@@ -825,10 +865,10 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
     double fScaleX = ( aGraphicSize.Width() - aCropRectangle.Left() - aCropRectangle.Right() ) / (double)nOldWidth;
     double fScaleY = ( aGraphicSize.Height() - aCropRectangle.Top() - aCropRectangle.Bottom() ) / (double)nOldHeight;
 
-    sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
-    sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
-    sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
-    sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
+    sal_Int32 nDiffLeft = aNewRect.Left() - aOutRect.Left();
+    sal_Int32 nDiffTop = aNewRect.Top() - aOutRect.Top();
+    sal_Int32 nDiffRight = aNewRect.Right() - aOutRect.Right();
+    sal_Int32 nDiffBottom = aNewRect.Bottom() - aOutRect.Bottom();
 
     // Compute new values in 10th of mm
     sal_Int32 nLeftCrop = static_cast<sal_Int32>( aCropRectangle.Left() + nDiffLeft * fScaleX );
@@ -854,31 +894,117 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
     aSz.SetHeight(aNewRect.GetHeight());
     pFormat->GetDoc()->SetAttr( aSz, *pFormat );
 
+    if(bIsTransformableSwFrame)
+    {
+        // Need to correct the TopLeft position in rotated state to make
+        // the interaction look correct. First, extract rotation (and others
+        // currently not used)
+        basegfx::B2DVector aScale, aTranslate;
+        double fRotate, fShearX;
+        GetFlyFrame()->getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+        // calc the center of the unchanged object
+        const basegfx::B2DPoint aFormerCenter(
+            GetFlyFrame()->getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
+
+        // define the existing rotaiton around that former center
+        const basegfx::B2DHomMatrix aRotFormerCenter(
+            basegfx::utils::createRotateAroundPoint(
+                aFormerCenter.getX(),
+                aFormerCenter.getY(),
+                fRotate));
+
+        // use the new center of the unrotated object, rotate it around the
+        // former center
+        const Point aNewCenter(aNewRect.Center());
+        const basegfx::B2DPoint aRotNewCenter(
+            aRotFormerCenter * basegfx::B2DPoint(aNewCenter.X(), aNewCenter.Y()));
+
+        // Create the new TopLeft of the unrotated, cropped object by creating
+        // as if re-rceating the unrotated geometry
+        const Point aNewTopLeft(
+            basegfx::fround(aRotNewCenter.getX() - (0.5 * aNewRect.getWidth())),
+            basegfx::fround(aRotNewCenter.getY() - (0.5 * aNewRect.getHeight())));
+
+        // checvk if we have movement and execute if yes
+        const Size aDeltaMove(
+            basegfx::fround(aNewTopLeft.getX() - aOutRect.Left()),
+            basegfx::fround(aNewTopLeft.getY() - aOutRect.Top()));
+
+        if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
+        {
+            NbcMove(aDeltaMove);
+        }
+    }
+
 //    pSh->EndUndo(SwUndoId::END);
     pSh->EndAllAction();
-
 }
 
-void SwVirtFlyDrawObj::NbcResize(const Point& rRef,
-            const Fraction& xFact, const Fraction& yFact)
+void SwVirtFlyDrawObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
 {
-    ResizeRect( aOutRect, rRef, xFact, yFact );
-
     const SwFrame* pTmpFrame = GetFlyFrame()->GetAnchorFrame();
+
     if( !pTmpFrame )
+    {
         pTmpFrame = GetFlyFrame();
-    const bool bVertX = pTmpFrame->IsVertical();
+    }
+
+    const bool bVertX(pTmpFrame->IsVertical());
+    const bool bRTL(pTmpFrame->IsRightToLeft());
+    const bool bVertL2RX(pTmpFrame->IsVertLR());
+    const bool bUseRightEdge((bVertX && !bVertL2RX ) || bRTL);
+    const bool bIsTransformableSwFrame(
+        GetFlyFrame()->IsFlyFreeFrame() &&
+        static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
+
+    if(bIsTransformableSwFrame)
+    {
+        // When we have a change in transformed state, we need to fall back to the
+        // state without possible transformations.
+        // In the Resize case to correctly handle the changes, apply to the transformation
+        // and extract the new, untransformed state from that modified transformation
+        basegfx::B2DHomMatrix aNewMat(GetFlyFrame()->getFrameAreaTransformation());
+        const basegfx::B2DPoint aRef(rRef.X(), rRef.Y());
+
+        // apply state to already valid transformation
+        aNewMat.translate(-aRef.getX(), -aRef.getY());
+        aNewMat.scale(double(xFact), double(yFact));
+        aNewMat.translate(aRef.getX(), aRef.getY());
+
+        // get center of transfomed state
+        const basegfx::B2DPoint aCenter(aNewMat * basegfx::B2DPoint(0.5, 0.5));
+
+        // decompose to extract scale
+        basegfx::B2DVector aScale, aTranslate;
+        double fRotate, fShearX;
+        aNewMat.decompose(aScale, aTranslate, fRotate, fShearX);
+
+        // create new modified OutRect
+        aOutRect = tools::Rectangle(
+            basegfx::fround(aCenter.getX() - (0.5 * aScale.getX())),
+            basegfx::fround(aCenter.getY() - (0.5 * aScale.getY())),
+            basegfx::fround(aCenter.getX() + (0.5 * aScale.getX())),
+            basegfx::fround(aCenter.getY() + (0.5 * aScale.getY())));
+
+        // restore FrameAreas so that actions below not adapted to new
+        // full transformations take the correct actions
+        TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+        pTransformableSwFrame->restoreFrameAreas();
+    }
+    else
+    {
+        ResizeRect( aOutRect, rRef, xFact, yFact );
+    }
 
-    const bool bRTL = pTmpFrame->IsRightToLeft();
+    // Position may also change, remember old one. This ois now already
+    // the one in the unrotated, old coordinate system
+    Point aOldPos(bUseRightEdge ? GetFlyFrame()->getFrameArea().TopRight() : GetFlyFrame()->getFrameArea().Pos());
 
-    const bool bVertL2RX = pTmpFrame->IsVertLR();
-    const Point aNewPos( ( bVertX && !bVertL2RX ) || bRTL ?
-                         aOutRect.Right() + 1 :
-                         aOutRect.Left(),
-                         aOutRect.Top() );
+    // get target size in old coordinate system
+    Size aSz( aOutRect.Right() - aOutRect.Left() + 1, aOutRect.Bottom()- aOutRect.Top()  + 1 );
 
-    Size aSz( aOutRect.Right() - aOutRect.Left() + 1,
-              aOutRect.Bottom()- aOutRect.Top()  + 1 );
+    // compare with restored FrameArea
     if( aSz != GetFlyFrame()->getFrameArea().SSize() )
     {
         //The width of the columns should not be too narrow
@@ -903,6 +1029,7 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef,
         const SwFormatFrameSize aOldFrameSz( pFormat->GetFrameSize() );
         GetFlyFrame()->ChgSize( aSz );
         SwFormatFrameSize aFrameSz( pFormat->GetFrameSize() );
+
         if ( aFrameSz.GetWidthPercent() || aFrameSz.GetHeightPercent() )
         {
             long nRelWidth, nRelHeight;
@@ -910,6 +1037,7 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef,
                                 GetFlyFrame()->GetAnchorFrame() :
                                 GetFlyFrame()->GetAnchorFrame()->GetUpper();
             const SwViewShell *pSh = GetFlyFrame()->getRootFrame()->GetCurrShell();
+
             if ( pSh && pRel->IsBodyFrame() &&
                  pSh->GetViewOptions()->getBrowseMode() &&
                  pSh->VisArea().HasArea() )
@@ -924,40 +1052,50 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef,
                 nRelWidth  = pRel->getFramePrintArea().Width();
                 nRelHeight = pRel->getFramePrintArea().Height();
             }
+
             if ( aFrameSz.GetWidthPercent() && aFrameSz.GetWidthPercent() != SwFormatFrameSize::SYNCED &&
                  aOldFrameSz.GetWidth() != aFrameSz.GetWidth() )
+            {
                 aFrameSz.SetWidthPercent( sal_uInt8(aSz.Width() * 100.0 / nRelWidth + 0.5) );
+            }
+
             if ( aFrameSz.GetHeightPercent() && aFrameSz.GetHeightPercent() != SwFormatFrameSize::SYNCED &&
                  aOldFrameSz.GetHeight() != aFrameSz.GetHeight() )
+            {
                 aFrameSz.SetHeightPercent( sal_uInt8(aSz.Height() * 100.0 / nRelHeight + 0.5) );
+            }
+
             pFormat->GetDoc()->SetAttr( aFrameSz, *pFormat );
         }
     }
 
-    //Position can also be changed!
-    const Point aOldPos( ( bVertX && !bVertL2RX ) || bRTL ?
-                         GetFlyFrame()->getFrameArea().TopRight() :
-                         GetFlyFrame()->getFrameArea().Pos() );
+    //Position can also be changed, get new one
+    const Point aNewPos(bUseRightEdge ? aOutRect.Right() + 1 : aOutRect.Left(), aOutRect.Top());
+
     if ( aNewPos != aOldPos )
     {
-        //May have been altered by the ChgSize!
-        if( bVertX || bRTL )
+        // Former late change in aOutRect by ChgSize
+        // is now taken into account directly by calculating
+        // aNewPos *after* calling ChgSize (see old code).
+        // Still need to adapt aOutRect since the 'Move' is already applied
+        // here (see ResizeRect) and it's the same SdrObject
+        const Size aDeltaMove(
+                aNewPos.X() - aOldPos.X(),
+                aNewPos.Y() - aOldPos.Y());
+        MoveRect(aOutRect, Size(-aDeltaMove.Width(), -aDeltaMove.Height()));
+
+        // Now, move as needed (no empty delta which was a hack anyways)
+        if(bIsTransformableSwFrame)
         {
-            if( aOutRect.TopRight() != aNewPos )
-            {
-                SwTwips nDeltaX;
-                if ( bVertL2RX )
-                    nDeltaX = aNewPos.X() - aOutRect.Left();
-                else
-                    nDeltaX = aNewPos.X() - aOutRect.Right();
-                SwTwips nDeltaY = aNewPos.Y() - aOutRect.Top();
-                MoveRect( aOutRect, Size( nDeltaX, nDeltaY ) );
-            }
+            // need to save aOutRect to FrameArea, will be restored to aOutRect in
+            // SwVirtFlyDrawObj::NbcMove currently for TransformableSwFrames
+            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*GetFlyFrame());
+            aFrm.setSwRect(aOutRect);
         }
-        else if ( aOutRect.TopLeft() != aNewPos )
-            aOutRect.SetPos( aNewPos );
+
+        // keep old hack - not clear what happens here
         bInResize = true;
-        NbcMove( Size( 0, 0 ) );
+        NbcMove(aDeltaMove);
         bInResize = false;
     }
 }
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index 429ff26b25e8..5334a0269447 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -26,7 +26,7 @@
 // #i28701#
 class SwFlyAtContentFrame;
 
-double getFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
+double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
 
 // Base class for those Flys that can "move freely" or better that are not
 // bound in Content.
@@ -63,7 +63,7 @@ private:
     // RotateFlyFrame3 - Support for outer Frame of a SwGrfNode
     // Only for local data extraction. To uniquely access information
     // for local transformation, use getFrameArea(Print)Transformation
-    double getFrameRotation() const;
+    double getLocalFrameRotation() const;
 
 protected:
     // #i28701# - new friend class <SwFlyNotify> for access to
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index b8a2d7ab0370..811bd390d82d 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -29,8 +29,8 @@
 #include <svl/SfxBroadcaster.hxx>
 #include <o3tl/typed_flags_set.hxx>
 #include <IDocumentDrawModelAccess.hxx>
-
 #include <com/sun/star/style/TabStop.hpp>
+#include <basegfx/matrix/b2dhommatrix.hxx>
 
 class SwLayoutFrame;
 class SwRootFrame;
@@ -207,10 +207,7 @@ public:
     virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const;
 
     // RotateFlyFrame3 - Support for Transformations
-    // Diverse transformations, starting with a concrete translate that has
-    // to be mapped and currently directly changes SwRect(s) at SwFrames. For
-    // now stay on sigle actions (*_translate), bu tmaybe later unified to
-    // a single transform with a single B2DHomMatrix to apply
+    // Modify current transformations by applying given translation
     virtual void transform_translate(const Point& rOffset);
 };
 
@@ -228,7 +225,10 @@ private:
     basegfx::B2DHomMatrix   maFrameAreaTransformation;
     basegfx::B2DHomMatrix   maFramePrintAreaTransformation;
 
-    // last saved versions of SwRect(s) from SwFrameAreaDefinition
+    // last saved versions of SwRect(s) from SwFrameAreaDefinition,
+    // set from adaptFrameAreasToTransformations before modifying
+    // SwFrameAreaDefinition(s), used for restore from
+    // restoreFrameAreas
     SwRect                  maSavedFrameArea;
     SwRect                  maSavedFramePrintArea;
 
@@ -262,17 +262,17 @@ public:
     // Tooling method to reset the SwRect(s) in the current
     // SwFrameAreaDefinition which are already apapted to
     // Transformation back to the untransformed state that was
-    // last saved (see resetAreaDefinitionsToTransformed).
+    // last saved (see adaptFrameAreasToTransformations).
     // Only the SwRect(s) are changed back, not the transformations.
-    void resetAreaDefinitionsToUntransformed();
+    void restoreFrameAreas();
 
     // Re-Creates the SwRect(s) as BoundAreas based on the current
     // set Transformations, also saves the last SwRect(s) to the save
     // values.
-    void resetAreaDefinitionsToTransformed();
+    void adaptFrameAreasToTransformations();
 
-    // transform by given B2DHomMatrix
-    void doTransform(const basegfx::B2DHomMatrix aTransform);
+    // Modify current definitions by applying the given transformation
+    void transform(const basegfx::B2DHomMatrix aTransform);
 };
 
 /**
diff --git a/sw/source/core/inc/notxtfrm.hxx b/sw/source/core/inc/notxtfrm.hxx
index 6144b32e58eb..2726a4eb5071 100644
--- a/sw/source/core/inc/notxtfrm.hxx
+++ b/sw/source/core/inc/notxtfrm.hxx
@@ -44,8 +44,8 @@ private:
     // RotateFlyFrame3 - Support for inner frame of a SwGrfNode.
     // Only for local data extraction. To uniquely access information
     // for local transformation, use getFrameArea(Print)Transformation.
-    friend double getFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
-    double getFrameRotation() const;
+    friend double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
+    double getLocalFrameRotation() const;
 
 protected:
     virtual void MakeAll(vcl::RenderContext* pRenderContext) override;
diff --git a/sw/source/core/layout/fly.cxx b/sw/source/core/layout/fly.cxx
index a3c8890df118..684b989d76b8 100644
--- a/sw/source/core/layout/fly.cxx
+++ b/sw/source/core/layout/fly.cxx
@@ -1966,6 +1966,7 @@ Size SwFlyFrame::ChgSize( const Size& aNewSize )
             }
         }
     }
+
     if ( aAdjustedNewSize != getFrameArea().SSize() )
     {
         SwFrameFormat *pFormat = GetFormat();
diff --git a/sw/source/core/layout/flycnt.cxx b/sw/source/core/layout/flycnt.cxx
index 2b980f904c39..87d3bba45400 100644
--- a/sw/source/core/layout/flycnt.cxx
+++ b/sw/source/core/layout/flycnt.cxx
@@ -1371,9 +1371,7 @@ void SwFlyAtContentFrame::SetAbsPos( const Point &rNew )
         GetPageFrame()->MoveFly( this, pTmpPage );
 
     const Point aRelPos = bVert ? Point( -nY, nX ) : Point( nX, nY );
-
     ChgRelPos( aRelPos );
-
     GetFormat()->GetDoc()->GetIDocumentUndoRedo().EndUndo( SwUndoId::END, nullptr );
 
     if ( pOldPage != FindPageFrame() )
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
index 10c519fea697..8a8c714ef351 100644
--- a/sw/source/core/layout/flylay.cxx
+++ b/sw/source/core/layout/flylay.cxx
@@ -156,7 +156,7 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
     const int nLoopControlMax = 10;
 
     // RotateFlyFrame3 - outer frame
-    const double fRotation(getFrameRotation());
+    const double fRotation(getLocalFrameRotation());
     const bool bRotated(!basegfx::fTools::equalZero(fRotation));
 
     if(bRotated)
@@ -166,7 +166,7 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
         // needed. Reset to BoundAreas will be done below automatically
         if(isTransformableSwFrame())
         {
-            getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+            getTransformableSwFrame()->restoreFrameAreas();
         }
     }
 
@@ -264,7 +264,7 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
         getTransformableSwFrame()->createFrameAreaTransformations(
             fRotation,
             aB2DCenter);
-        getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+        getTransformableSwFrame()->adaptFrameAreasToTransformations();
     }
     else
     {
@@ -323,17 +323,17 @@ void SwFlyFreeFrame::transform_translate(const Point& rOffset)
                 rOffset.X(), rOffset.Y()));
 
         // transform using TransformableSwFrame
-        getTransformableSwFrame()->doTransform(aTransform);
+        getTransformableSwFrame()->transform(aTransform);
     }
 }
 
 // RotateFlyFrame3 - outer frame
-double getFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame)
+double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame)
 {
-    return rNoTextFrame.getFrameRotation();
+    return rNoTextFrame.getLocalFrameRotation();
 }
 
-double SwFlyFreeFrame::getFrameRotation() const
+double SwFlyFreeFrame::getLocalFrameRotation() const
 {
     // SwLayoutFrame::Lower() != SwFrame::GetLower(), but SwFrame::GetLower()
     // calls SwLayoutFrame::Lower() when it's a SwLayoutFrame - so use GetLower()
@@ -341,7 +341,7 @@ double SwFlyFreeFrame::getFrameRotation() const
 
     if(nullptr != pSwNoTextFrame)
     {
-        return getFrameRotation_from_SwNoTextFrame(*pSwNoTextFrame);
+        return getLocalFrameRotation_from_SwNoTextFrame(*pSwNoTextFrame);
     }
 
     // no rotation
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 4cd9245eb2f0..7f7068ed0362 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -166,7 +166,7 @@ void TransformableSwFrame::createFrameAreaTransformations(
         rFramePrintArea.Left() + rFrameArea.Left(), rFramePrintArea.Top() + rFrameArea.Top());
 }
 
-void TransformableSwFrame::resetAreaDefinitionsToTransformed()
+void TransformableSwFrame::adaptFrameAreasToTransformations()
 {
     if(!getLocalFrameAreaTransformation().isIdentity())
     {
@@ -203,7 +203,7 @@ void TransformableSwFrame::resetAreaDefinitionsToTransformed()
     }
 }
 
-void TransformableSwFrame::resetAreaDefinitionsToUntransformed()
+void TransformableSwFrame::restoreFrameAreas()
 {
     // This can be done fully based on the Transformations currently
     // set (and I did this in the beginning and it may be necessary
@@ -224,7 +224,7 @@ void TransformableSwFrame::resetAreaDefinitionsToUntransformed()
 }
 
 // transform by given B2DHomMatrix
-void TransformableSwFrame::doTransform(const basegfx::B2DHomMatrix aTransform)
+void TransformableSwFrame::transform(const basegfx::B2DHomMatrix aTransform)
 {
     if(!aTransform.isIdentity())
     {
commit 7d391f9a563041aae416c7017dcec36bbf4dfb2c
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Nov 9 15:53:33 2017 +0100

    RotateFlyFrame3: Restructured TransformableSwFrame
    
    No longer derive a SwFrame that needs Transformation
    support from TransformableSwFrame, but keep it as a
    member (in a std::unique_ptr). Adapted all usages,
    also added reset of local SwRect(s) in local SwFrameAreaDefinition
    during layouting. That makes PrintPreview work correctly.
    
    Change-Id: I2e7720e67b57d4d29c0feb065878e246192a8a4c

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 897e9f6d1121..3971c9140da2 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -144,7 +144,8 @@ static void lcl_PaintReplacement( const SwRect &rRect, const OUString &rText,
 
 SwNoTextFrame::SwNoTextFrame(SwNoTextNode * const pNode, SwFrame* pSib )
 :   SwContentFrame( pNode, pSib ),
-    TransformableSwFrame()
+    // RotateFlyFrame3
+    mpTransformableSwFrame()
 {
     mnFrameType = SwFrameType::NoTxt;
 }
@@ -474,25 +475,41 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
     // RotateFlyFrame3 - inner frame. Get rotation and check if used
     const double fRotation(getFrameRotation());
     const bool bRotated(!basegfx::fTools::equalZero(fRotation));
-    SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
 
-    if(bRotated && pUpperFly && !pUpperFly->isFrameAreaDefinitionValid())
+    if(bRotated)
     {
-        // RotateFlyFrame3: outer frame *needs* to be layouted first, force this by calling
-        // it's ::Calc directly
-        pUpperFly->Calc(pRenderContext);
-    }
+        SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
 
-    if(bRotated && pUpperFly)
-    {
-        // Reset outer frame to unrotated state. This is necessary to make the
-        // layouting below work as currently implemented in Writer. As expected
-        // using Transformations allows to do this on the fly due to all information
-        // being included there.
-        // The full solution would be to adapt the whole layouting
-        // process of Writer to take care of Transformations, but that
-        // is currently beyond scope
-        pUpperFly->resetAreaDefinitionsToUntransformed(*pUpperFly);
+        if(pUpperFly)
+        {
+            if(!pUpperFly->isFrameAreaDefinitionValid())
+            {
+                // RotateFlyFrame3: outer frame *needs* to be layouted first, force this by calling
+                // it's ::Calc directly
+                pUpperFly->Calc(pRenderContext);
+            }
+
+            // Reset outer frame to unrotated state. This is necessary to make the
+            // layouting below work as currently implemented in Writer. As expected
+            // using Transformations allows to do this on the fly due to all information
+            // being included there.
+            // The full solution would be to adapt the whole layouting
+            // process of Writer to take care of Transformations, but that
+            // is currently beyond scope
+            if(pUpperFly->isTransformableSwFrame())
+            {
+                pUpperFly->getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+            }
+        }
+
+        // Re-layout may be partially (see all isFrameAreaDefinitionValid() flags),
+        // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is also
+        // needed (e.g. for PrintPreview).
+        // Reset to BoundAreas will be done below automatically
+        if(isTransformableSwFrame())
+        {
+            getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+        }
     }
 
     SwContentNotify aNotify( this );
@@ -519,15 +536,9 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
     }
 
     // RotateFlyFrame3 - inner frame
-    // After the unrotated layout is finished, apply possible set rotation to it
-    if(!bRotated)
+    if(bRotated)
     {
-        // reset transformations to show that they are not used
-        resetLocalAreaTransformations();
-    }
-    else
-    {
-        const bool bMeValid(isFrameAreaDefinitionValid());
+        SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
 
         if(pUpperFly)
         {
@@ -536,30 +547,41 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
             // the transformed SwFrame. All needed information is part
             // of the already correctly created Transformations of the
             // upper frame, so it can bre re-created on the fly
-            pUpperFly->resetAreaDefinitionsToTransformed(*pUpperFly);
+            if(pUpperFly->isTransformableSwFrame())
+            {
+                pUpperFly->getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+            }
         }
 
-        if(bMeValid)
+        // After the unrotated layout is finished, apply possible set rotation to it
+        // get center from outer frame (layout frame) to be on the safe side
+        const Point aCenter(GetUpper() ? GetUpper()->getFrameArea().Center() : getFrameArea().Center());
+        const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
+
+        if(!mpTransformableSwFrame)
         {

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list