Rebased ref, commits from common ancestor:
commit 8c103b56b91a3b5037300036b57e3d9f96d7255a
Author: Armin Le Grand <armin.le.gr...@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 001048900b8cbaa40675d15023f08a693e7f27a4
Author: Armin Le Grand <armin.le.gr...@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 cbcb2470872bd1fadb48da9265950e653eb3bf98
Author: Armin Le Grand <armin.le.gr...@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 d7fb6e735136a0fab09d066c0c7827a5782613cc
Author: Armin Le Grand <armin.le.gr...@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 11619367ab2baed07498d0144a23f8d45ddba410
Author: Armin Le Grand <armin.le.gr...@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 4d52c9e68e9c1b13b6febe17e42c685c076d0c46
Author: Armin Le Grand <armin.le.gr...@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
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to