[Libreoffice-commits] core.git: Branch 'feature/RotateFlyFrame3' - 626 commits - accessibility/inc accessibility/source animations/source avmedia/source basctl/source basegfx/source basic/inc basic/source bridges/source canvas/source chart2/source .clang-format codemaker/source comphelper/source compilerplugins/clang config_host/config_global.h.in config_host/config_qt5.h.in config_host.mk.in configmgr/source configure.ac connectivity/source cppcanvas/source cui/source cui/uiconfig dbaccess/source dbaccess/win32 desktop/qa desktop/source desktop/unx desktop/win32 dictionaries download.lst drawinglayer/source editeng/inc editeng/source embedserv/source emfio/inc emfio/source extensions/source external/breakpad external/cairo external/clucene external/curl external/epoxy external/expat external/graphite external/harfbuzz external/hunspell external/icu external/lcms2 external/libcdr external/libcmis external/libepubgen external/libfreehand external/libstaroffice external/libtommath external/libvisio external/libxml2 external/libxslt external/more_fonts external/msc-externals external/openldap external/openssl external/pdfium external/postgresql external/redland external/xmlsec extras/source filter/Configuration_filter.mk filter/source forms/source formula/source fpicker/source fpicker/uiconfig framework/inc framework/qa framework/source .git-hooks/pre-commit helpcontent2 hwpfilter/source i18nlangtag/source i18npool/inc i18npool/source i18nutil/source icon-themes/elementary idlc/inc idlc/source include/basegfx include/basic include/canvas include/codemaker include/com include/comphelper include/connectivity include/drawinglayer include/editeng include/filter include/i18nlangtag include/i18nutil include/jvmfwk include/LibreOfficeKit include/linguistic include/oox include/package include/registry include/rtl include/sal include/sax include/sfx2 include/sot include/store include/svl include/svtools include/svx include/test include/tools include/ucbhelper include/unotools include/v bahelper include/vcl ios/LibreOfficeKit ios/LibreOfficeLight ios/loApp.xcconfig.in jvmfwk/plugins jvmfwk/source l10ntools/inc librelogo/source libreofficekit/qa lingucomponent/source linguistic/source lotuswordpro/inc lotuswordpro/source Makefile.fetch Makefile.in mysqlc/source odk/examples odk/settings offapi/com officecfg/registry oovbaapi/ooo oox/inc oox/source opencl/inc package/inc package/source postprocess/CustomTarget_signing.mk pyuno/source qadevOOo/Jar_OOoRunner.mk qadevOOo/objdsc qadevOOo/runner qadevOOo/tests readlicense_oo/license README.md registry/inc registry/source registry/tools reportdesign/inc reportdesign/source RepositoryExternal.mk Repository.mk sal/osl sal/qa sal/rtl sal/textenc sax/source scaddins/source sc/CppunitTest_sc_cellrangeobj.mk sc/CppunitTest_sc_condformats.mk sc/CppunitTest_sc_labelrangeobj.mk sc/CppunitTest_sc_labelrangesobj.mk sc/CppunitTest_sc_pivottable_filters_test.mk sc/CppunitTest_sc_scenariosobj.mk sc/CppunitTest_sc_tableconditionalentryob j.mk sc/CppunitTest_sc_tableconditionalformatobj.mk sc/CppunitTest_sc_tablevalidationobj.mk sc/inc sc/Library_scfilt.mk sc/Module_sc.mk scp2/InstallScript_setup_osl.mk scp2/Module_scp2.mk sc/qa scripting/source sc/source sdext/README sdext/source sd/inc sd/Module_sd.mk sd/qa sd/source sd/uiconfig sd/UIConfig_simpress.mk sfx2/source shell/source slideshow/source solenv/clang-format solenv/CompilerTest_compilerplugins_clang.mk solenv/flatpak-manifest.in solenv/gbuild solenv/gdb solenv/vs sot/source starmath/source stoc/source store/source svl/qa svl/source svtools/inc svtools/source svx/inc svx/Library_svx.mk svx/sdi svx/source svx/uiconfig sw/CppunitTest_sw_ooxmlexport10.mk sw/inc sw/qa sw/sdi sw/source sw/uiconfig sysui/CustomTarget_share.mk test/Library_subsequenttest.mk test/source toolkit/source tools/Library_tl.mk tools/source translations ucbhelper/source ucb/source unotools/source uui/source vbahelper/source vcl/android vcl/CppunitTest_vcl_complextext.mk vcl/CustomTarget_qt5_m oc.mk vcl/Executable_diffuzzer.mk vcl/Executable_scrtffuzzer.mk vcl/Executable_wksfuzzer.mk vcl/Executable_xlsfuzzer.mk vcl/headless vcl/inc vcl/ios vcl/Library_vcl.mk vcl/Library_vclplug_kde5.mk vcl/Library_vclplug_qt5.mk vcl/Module_vcl.mk vcl/opengl vcl/osx vcl/qa vcl/qt5 vcl/quartz vcl/source vcl/unx vcl/win vcl/workben winaccessibility/source wizards/source writerfilter/source xmloff/source xmlscript/source xmlsecurity/inc xmlsecurity/qa xmlsecurity/source

Armin Le Grand Armin.Le.Grand at cib.de
Tue Nov 14 20:39:15 UTC 2017


Rebased ref, commits from common ancestor:
commit 43658985c8a68cf6ef53182a527f13f8288c95bf
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Tue Nov 14 18:07:32 2017 +0100

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

diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index cb436581adf2..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;
commit 75c522ac031e3ca8fa38ffd35f2e1914f13b0772
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Tue Nov 14 18:07:32 2017 +0100

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

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 3971c9140da2..9432576bdcf4 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -473,7 +473,7 @@ const Size& SwNoTextFrame::GetSize() const
 void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
 {
     // RotateFlyFrame3 - inner frame. Get rotation and check if used
-    const double fRotation(getFrameRotation());
+    const double fRotation(getLocalFrameRotation());
     const bool bRotated(!basegfx::fTools::equalZero(fRotation));
 
     if(bRotated)
@@ -498,7 +498,7 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
             // is currently beyond scope
             if(pUpperFly->isTransformableSwFrame())
             {
-                pUpperFly->getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+                pUpperFly->getTransformableSwFrame()->restoreFrameAreas();
             }
         }
 
@@ -508,7 +508,7 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
         // Reset to BoundAreas will be done below automatically
         if(isTransformableSwFrame())
         {
-            getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+            getTransformableSwFrame()->restoreFrameAreas();
         }
     }
 
@@ -549,7 +549,7 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
             // upper frame, so it can bre re-created on the fly
             if(pUpperFly->isTransformableSwFrame())
             {
-                pUpperFly->getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+                pUpperFly->getTransformableSwFrame()->adaptFrameAreasToTransformations();
             }
         }
 
@@ -566,7 +566,7 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
         getTransformableSwFrame()->createFrameAreaTransformations(
             fRotation,
             aB2DCenter);
-        getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+        getTransformableSwFrame()->adaptFrameAreasToTransformations();
     }
     else
     {
@@ -615,13 +615,13 @@ void SwNoTextFrame::transform_translate(const Point& rOffset)
                 rOffset.X(), rOffset.Y()));
 
         // transform using TransformableSwFrame
-        getTransformableSwFrame()->doTransform(aTransform);
+        getTransformableSwFrame()->transform(aTransform);
     }
 }
 
 // RotateFlyFrame3 - inner frame
 // Check if we contain a SwGrfNode and get possible rotation from it
-double SwNoTextFrame::getFrameRotation() const
+double SwNoTextFrame::getLocalFrameRotation() const
 {
     const SwNoTextNode* pSwNoTextNode(nullptr != GetNode() ? GetNode()->GetNoTextNode() : nullptr);
 
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index cc12dd1baad9..e1035a3754fa 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -630,9 +630,18 @@ void SwVirtFlyDrawObj::NbcSetLogicRect(const tools::Rectangle& )
 }
 
 //  SwVirtFlyDrawObj::Move() and Resize()
-
 void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
 {
+    if(GetFlyFrame()->IsFlyFreeFrame() && static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame())
+    {
+        // When we have a change in transformed state, we need to fall back to the
+        // state without possible transformations. Restore FrameArea and use aOutRect
+        // from old FrameArea. From here, all former actions below should be fine
+        TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+        pTransformableSwFrame->restoreFrameAreas();
+        aOutRect = GetFlyFrame()->getFrameArea().SVRect();
+    }
+
     MoveRect( aOutRect, rSiz );
     const Point aOldPos( GetFlyFrame()->getFrameArea().Pos() );
     const Point aNewPos( aOutRect.TopLeft() );
@@ -649,7 +658,9 @@ void SwVirtFlyDrawObj::NbcMove(const Size& rSiz)
     //anchor must be set. Anchor and the new RelPos is calculated and
     //placed by the Fly itself.
     if( GetFlyFrame()->IsFlyAtContentFrame() )
+    {
         static_cast<SwFlyAtContentFrame*>(GetFlyFrame())->SetAbsPos( aNewPos );
+    }
     else
     {
         const SwFrameFormat *pTmpFormat = GetFormat();
@@ -781,34 +792,63 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
 {
     // Get Wrt Shell
     SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() );
+
     if (!pSh)
+    {
         return;
+    }
+
+    GraphicObject const *pGraphicObject = pSh->GetGraphicObj();
+
+    if (!pGraphicObject)
+    {
+        return;
+    }
+
+    const bool bIsTransformableSwFrame(
+        GetFlyFrame()->IsFlyFreeFrame() &&
+        static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
+
+    if(bIsTransformableSwFrame)
+    {
+        // When we have a change in transformed state, we need to fall back to the
+        // state without possible transformations. Restore FrameArea and use aOutRect
+        // from old FrameArea. From here, all former actions below should be fine
+        TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+        pTransformableSwFrame->restoreFrameAreas();
+        aOutRect = GetFlyFrame()->getFrameArea().SVRect();
+    }
 
     // Compute old and new rect. This will give us the deformation to apply to
     // the object to crop
-    tools::Rectangle aOldRect( aOutRect );
-
-    const long nOldWidth = aOldRect.GetWidth();
-    const long nOldHeight = aOldRect.GetHeight();
+    const long nOldWidth(aOutRect.GetWidth());
+    const long nOldHeight(aOutRect.GetHeight());
 
     if (!nOldWidth || !nOldHeight)
+    {
         return;
+    }
 
     tools::Rectangle aNewRect( aOutRect );
     ResizeRect( aNewRect, rRef, xFact, yFact );
 
     // Get graphic object size in 100th of mm
-    GraphicObject const *pGraphicObject = pSh->GetGraphicObj();
-    if (!pGraphicObject)
-        return;
     const MapMode aMapMode100thmm(MapUnit::Map100thMM);
     Size aGraphicSize(pGraphicObject->GetPrefSize());
+
     if( MapUnit::MapPixel == pGraphicObject->GetPrefMapMode().GetMapUnit() )
+    {
         aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
+    }
     else
+    {
         aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, pGraphicObject->GetPrefMapMode(), aMapMode100thmm);
+    }
+
     if( aGraphicSize.Width() == 0 || aGraphicSize.Height() == 0 )
+    {
         return ;
+    }
 
     // Get old values for crop in 10th of mm
     SfxItemSet aSet( pSh->GetAttrPool(), svl::Items<RES_GRFATR_CROPGRF, RES_GRFATR_CROPGRF>{} );
@@ -825,10 +865,10 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
     double fScaleX = ( aGraphicSize.Width() - aCropRectangle.Left() - aCropRectangle.Right() ) / (double)nOldWidth;
     double fScaleY = ( aGraphicSize.Height() - aCropRectangle.Top() - aCropRectangle.Bottom() ) / (double)nOldHeight;
 
-    sal_Int32 nDiffLeft = aNewRect.Left() - aOldRect.Left();
-    sal_Int32 nDiffTop = aNewRect.Top() - aOldRect.Top();
-    sal_Int32 nDiffRight = aNewRect.Right() - aOldRect.Right();
-    sal_Int32 nDiffBottom = aNewRect.Bottom() - aOldRect.Bottom();
+    sal_Int32 nDiffLeft = aNewRect.Left() - aOutRect.Left();
+    sal_Int32 nDiffTop = aNewRect.Top() - aOutRect.Top();
+    sal_Int32 nDiffRight = aNewRect.Right() - aOutRect.Right();
+    sal_Int32 nDiffBottom = aNewRect.Bottom() - aOutRect.Bottom();
 
     // Compute new values in 10th of mm
     sal_Int32 nLeftCrop = static_cast<sal_Int32>( aCropRectangle.Left() + nDiffLeft * fScaleX );
@@ -854,31 +894,117 @@ void SwVirtFlyDrawObj::NbcCrop(const Point& rRef, const Fraction& xFact, const F
     aSz.SetHeight(aNewRect.GetHeight());
     pFormat->GetDoc()->SetAttr( aSz, *pFormat );
 
+    if(bIsTransformableSwFrame)
+    {
+        // Need to correct the TopLeft position in rotated state to make
+        // the interaction look correct. First, extract rotation (and others
+        // currently not used)
+        basegfx::B2DVector aScale, aTranslate;
+        double fRotate, fShearX;
+        GetFlyFrame()->getFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+
+        // calc the center of the unchanged object
+        const basegfx::B2DPoint aFormerCenter(
+            GetFlyFrame()->getFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
+
+        // define the existing rotaiton around that former center
+        const basegfx::B2DHomMatrix aRotFormerCenter(
+            basegfx::utils::createRotateAroundPoint(
+                aFormerCenter.getX(),
+                aFormerCenter.getY(),
+                fRotate));
+
+        // use the new center of the unrotated object, rotate it around the
+        // former center
+        const Point aNewCenter(aNewRect.Center());
+        const basegfx::B2DPoint aRotNewCenter(
+            aRotFormerCenter * basegfx::B2DPoint(aNewCenter.X(), aNewCenter.Y()));
+
+        // Create the new TopLeft of the unrotated, cropped object by creating
+        // as if re-rceating the unrotated geometry
+        const Point aNewTopLeft(
+            basegfx::fround(aRotNewCenter.getX() - (0.5 * aNewRect.getWidth())),
+            basegfx::fround(aRotNewCenter.getY() - (0.5 * aNewRect.getHeight())));
+
+        // checvk if we have movement and execute if yes
+        const Size aDeltaMove(
+            basegfx::fround(aNewTopLeft.getX() - aOutRect.Left()),
+            basegfx::fround(aNewTopLeft.getY() - aOutRect.Top()));
+
+        if(0 != aDeltaMove.Width() || 0 != aDeltaMove.Height())
+        {
+            NbcMove(aDeltaMove);
+        }
+    }
+
 //    pSh->EndUndo(SwUndoId::END);
     pSh->EndAllAction();
-
 }
 
-void SwVirtFlyDrawObj::NbcResize(const Point& rRef,
-            const Fraction& xFact, const Fraction& yFact)
+void SwVirtFlyDrawObj::NbcResize(const Point& rRef, const Fraction& xFact, const Fraction& yFact)
 {
-    ResizeRect( aOutRect, rRef, xFact, yFact );
-
     const SwFrame* pTmpFrame = GetFlyFrame()->GetAnchorFrame();
+
     if( !pTmpFrame )
+    {
         pTmpFrame = GetFlyFrame();
-    const bool bVertX = pTmpFrame->IsVertical();
+    }
+
+    const bool bVertX(pTmpFrame->IsVertical());
+    const bool bRTL(pTmpFrame->IsRightToLeft());
+    const bool bVertL2RX(pTmpFrame->IsVertLR());
+    const bool bUseRightEdge((bVertX && !bVertL2RX ) || bRTL);
+    const bool bIsTransformableSwFrame(
+        GetFlyFrame()->IsFlyFreeFrame() &&
+        static_cast<SwFlyFreeFrame*>(GetFlyFrame())->isTransformableSwFrame());
+
+    if(bIsTransformableSwFrame)
+    {
+        // When we have a change in transformed state, we need to fall back to the
+        // state without possible transformations.
+        // In the Resize case to correctly handle the changes, apply to the transformation
+        // and extract the new, untransformed state from that modified transformation
+        basegfx::B2DHomMatrix aNewMat(GetFlyFrame()->getFrameAreaTransformation());
+        const basegfx::B2DPoint aRef(rRef.X(), rRef.Y());
+
+        // apply state to already valid transformation
+        aNewMat.translate(-aRef.getX(), -aRef.getY());
+        aNewMat.scale(double(xFact), double(yFact));
+        aNewMat.translate(aRef.getX(), aRef.getY());
+
+        // get center of transfomed state
+        const basegfx::B2DPoint aCenter(aNewMat * basegfx::B2DPoint(0.5, 0.5));
+
+        // decompose to extract scale
+        basegfx::B2DVector aScale, aTranslate;
+        double fRotate, fShearX;
+        aNewMat.decompose(aScale, aTranslate, fRotate, fShearX);
+
+        // create new modified OutRect
+        aOutRect = tools::Rectangle(
+            basegfx::fround(aCenter.getX() - (0.5 * aScale.getX())),
+            basegfx::fround(aCenter.getY() - (0.5 * aScale.getY())),
+            basegfx::fround(aCenter.getX() + (0.5 * aScale.getX())),
+            basegfx::fround(aCenter.getY() + (0.5 * aScale.getY())));
+
+        // restore FrameAreas so that actions below not adapted to new
+        // full transformations take the correct actions
+        TransformableSwFrame* pTransformableSwFrame(static_cast<SwFlyFreeFrame*>(GetFlyFrame())->getTransformableSwFrame());
+        pTransformableSwFrame->restoreFrameAreas();
+    }
+    else
+    {
+        ResizeRect( aOutRect, rRef, xFact, yFact );
+    }
 
-    const bool bRTL = pTmpFrame->IsRightToLeft();
+    // Position may also change, remember old one. This ois now already
+    // the one in the unrotated, old coordinate system
+    Point aOldPos(bUseRightEdge ? GetFlyFrame()->getFrameArea().TopRight() : GetFlyFrame()->getFrameArea().Pos());
 
-    const bool bVertL2RX = pTmpFrame->IsVertLR();
-    const Point aNewPos( ( bVertX && !bVertL2RX ) || bRTL ?
-                         aOutRect.Right() + 1 :
-                         aOutRect.Left(),
-                         aOutRect.Top() );
+    // get target size in old coordinate system
+    Size aSz( aOutRect.Right() - aOutRect.Left() + 1, aOutRect.Bottom()- aOutRect.Top()  + 1 );
 
-    Size aSz( aOutRect.Right() - aOutRect.Left() + 1,
-              aOutRect.Bottom()- aOutRect.Top()  + 1 );
+    // compare with restored FrameArea
     if( aSz != GetFlyFrame()->getFrameArea().SSize() )
     {
         //The width of the columns should not be too narrow
@@ -903,6 +1029,7 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef,
         const SwFormatFrameSize aOldFrameSz( pFormat->GetFrameSize() );
         GetFlyFrame()->ChgSize( aSz );
         SwFormatFrameSize aFrameSz( pFormat->GetFrameSize() );
+
         if ( aFrameSz.GetWidthPercent() || aFrameSz.GetHeightPercent() )
         {
             long nRelWidth, nRelHeight;
@@ -910,6 +1037,7 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef,
                                 GetFlyFrame()->GetAnchorFrame() :
                                 GetFlyFrame()->GetAnchorFrame()->GetUpper();
             const SwViewShell *pSh = GetFlyFrame()->getRootFrame()->GetCurrShell();
+
             if ( pSh && pRel->IsBodyFrame() &&
                  pSh->GetViewOptions()->getBrowseMode() &&
                  pSh->VisArea().HasArea() )
@@ -924,40 +1052,50 @@ void SwVirtFlyDrawObj::NbcResize(const Point& rRef,
                 nRelWidth  = pRel->getFramePrintArea().Width();
                 nRelHeight = pRel->getFramePrintArea().Height();
             }
+
             if ( aFrameSz.GetWidthPercent() && aFrameSz.GetWidthPercent() != SwFormatFrameSize::SYNCED &&
                  aOldFrameSz.GetWidth() != aFrameSz.GetWidth() )
+            {
                 aFrameSz.SetWidthPercent( sal_uInt8(aSz.Width() * 100.0 / nRelWidth + 0.5) );
+            }
+
             if ( aFrameSz.GetHeightPercent() && aFrameSz.GetHeightPercent() != SwFormatFrameSize::SYNCED &&
                  aOldFrameSz.GetHeight() != aFrameSz.GetHeight() )
+            {
                 aFrameSz.SetHeightPercent( sal_uInt8(aSz.Height() * 100.0 / nRelHeight + 0.5) );
+            }
+
             pFormat->GetDoc()->SetAttr( aFrameSz, *pFormat );
         }
     }
 
-    //Position can also be changed!
-    const Point aOldPos( ( bVertX && !bVertL2RX ) || bRTL ?
-                         GetFlyFrame()->getFrameArea().TopRight() :
-                         GetFlyFrame()->getFrameArea().Pos() );
+    //Position can also be changed, get new one
+    const Point aNewPos(bUseRightEdge ? aOutRect.Right() + 1 : aOutRect.Left(), aOutRect.Top());
+
     if ( aNewPos != aOldPos )
     {
-        //May have been altered by the ChgSize!
-        if( bVertX || bRTL )
+        // Former late change in aOutRect by ChgSize
+        // is now taken into account directly by calculating
+        // aNewPos *after* calling ChgSize (see old code).
+        // Still need to adapt aOutRect since the 'Move' is already applied
+        // here (see ResizeRect) and it's the same SdrObject
+        const Size aDeltaMove(
+                aNewPos.X() - aOldPos.X(),
+                aNewPos.Y() - aOldPos.Y());
+        MoveRect(aOutRect, Size(-aDeltaMove.Width(), -aDeltaMove.Height()));
+
+        // Now, move as needed (no empty delta which was a hack anyways)
+        if(bIsTransformableSwFrame)
         {
-            if( aOutRect.TopRight() != aNewPos )
-            {
-                SwTwips nDeltaX;
-                if ( bVertL2RX )
-                    nDeltaX = aNewPos.X() - aOutRect.Left();
-                else
-                    nDeltaX = aNewPos.X() - aOutRect.Right();
-                SwTwips nDeltaY = aNewPos.Y() - aOutRect.Top();
-                MoveRect( aOutRect, Size( nDeltaX, nDeltaY ) );
-            }
+            // need to save aOutRect to FrameArea, will be restored to aOutRect in
+            // SwVirtFlyDrawObj::NbcMove currently for TransformableSwFrames
+            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*GetFlyFrame());
+            aFrm.setSwRect(aOutRect);
         }
-        else if ( aOutRect.TopLeft() != aNewPos )
-            aOutRect.SetPos( aNewPos );
+
+        // keep old hack - not clear what happens here
         bInResize = true;
-        NbcMove( Size( 0, 0 ) );
+        NbcMove(aDeltaMove);
         bInResize = false;
     }
 }
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index 429ff26b25e8..5334a0269447 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -26,7 +26,7 @@
 // #i28701#
 class SwFlyAtContentFrame;
 
-double getFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
+double getLocalFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
 
 // Base class for those Flys that can "move freely" or better that are not
 // bound in Content.
@@ -63,7 +63,7 @@ private:
     // RotateFlyFrame3 - Support for outer Frame of a SwGrfNode
     // Only for local data extraction. To uniquely access information
     // for local transformation, use getFrameArea(Print)Transformation
-    double getFrameRotation() const;
+    double getLocalFrameRotation() const;
 
 protected:
     // #i28701# - new friend class <SwFlyNotify> for access to
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index b8a2d7ab0370..cb436581adf2 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -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 eab9a72072f841a29533747c5e6affe0e720517a
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Nov 9 15:53:33 2017 +0100

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

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 897e9f6d1121..3971c9140da2 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -144,7 +144,8 @@ static void lcl_PaintReplacement( const SwRect &rRect, const OUString &rText,
 
 SwNoTextFrame::SwNoTextFrame(SwNoTextNode * const pNode, SwFrame* pSib )
 :   SwContentFrame( pNode, pSib ),
-    TransformableSwFrame()
+    // RotateFlyFrame3
+    mpTransformableSwFrame()
 {
     mnFrameType = SwFrameType::NoTxt;
 }
@@ -474,25 +475,41 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
     // RotateFlyFrame3 - inner frame. Get rotation and check if used
     const double fRotation(getFrameRotation());
     const bool bRotated(!basegfx::fTools::equalZero(fRotation));
-    SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
 
-    if(bRotated && pUpperFly && !pUpperFly->isFrameAreaDefinitionValid())
+    if(bRotated)
     {
-        // RotateFlyFrame3: outer frame *needs* to be layouted first, force this by calling
-        // it's ::Calc directly
-        pUpperFly->Calc(pRenderContext);
-    }
+        SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
 
-    if(bRotated && pUpperFly)
-    {
-        // Reset outer frame to unrotated state. This is necessary to make the
-        // layouting below work as currently implemented in Writer. As expected
-        // using Transformations allows to do this on the fly due to all information
-        // being included there.
-        // The full solution would be to adapt the whole layouting
-        // process of Writer to take care of Transformations, but that
-        // is currently beyond scope
-        pUpperFly->resetAreaDefinitionsToUntransformed(*pUpperFly);
+        if(pUpperFly)
+        {
+            if(!pUpperFly->isFrameAreaDefinitionValid())
+            {
+                // RotateFlyFrame3: outer frame *needs* to be layouted first, force this by calling
+                // it's ::Calc directly
+                pUpperFly->Calc(pRenderContext);
+            }
+
+            // Reset outer frame to unrotated state. This is necessary to make the
+            // layouting below work as currently implemented in Writer. As expected
+            // using Transformations allows to do this on the fly due to all information
+            // being included there.
+            // The full solution would be to adapt the whole layouting
+            // process of Writer to take care of Transformations, but that
+            // is currently beyond scope
+            if(pUpperFly->isTransformableSwFrame())
+            {
+                pUpperFly->getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+            }
+        }
+
+        // Re-layout may be partially (see all isFrameAreaDefinitionValid() flags),
+        // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is also
+        // needed (e.g. for PrintPreview).
+        // Reset to BoundAreas will be done below automatically
+        if(isTransformableSwFrame())
+        {
+            getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+        }
     }
 
     SwContentNotify aNotify( this );
@@ -519,15 +536,9 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
     }
 
     // RotateFlyFrame3 - inner frame
-    // After the unrotated layout is finished, apply possible set rotation to it
-    if(!bRotated)
+    if(bRotated)
     {
-        // reset transformations to show that they are not used
-        resetLocalAreaTransformations();
-    }
-    else
-    {
-        const bool bMeValid(isFrameAreaDefinitionValid());
+        SwFlyFreeFrame* pUpperFly(dynamic_cast< SwFlyFreeFrame* >(GetUpper()));
 
         if(pUpperFly)
         {
@@ -536,30 +547,41 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
             // the transformed SwFrame. All needed information is part
             // of the already correctly created Transformations of the
             // upper frame, so it can bre re-created on the fly
-            pUpperFly->resetAreaDefinitionsToTransformed(*pUpperFly);
+            if(pUpperFly->isTransformableSwFrame())
+            {
+                pUpperFly->getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+            }
         }
 
-        if(bMeValid)
+        // After the unrotated layout is finished, apply possible set rotation to it
+        // get center from outer frame (layout frame) to be on the safe side
+        const Point aCenter(GetUpper() ? GetUpper()->getFrameArea().Center() : getFrameArea().Center());
+        const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
+
+        if(!mpTransformableSwFrame)
         {
-            // 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());
-
-            updateTransformationsAndFrameAreaDefinitions(
-                *this,
-                fRotation,
-                aB2DCenter);
+            mpTransformableSwFrame.reset(new TransformableSwFrame(*this));
         }
+
+        getTransformableSwFrame()->createFrameAreaTransformations(
+            fRotation,
+            aB2DCenter);
+        getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+    }
+    else
+    {
+        // reset transformations to show that they are not used
+        mpTransformableSwFrame.reset();
     }
 }
 
 // RotateFlyFrame3 - Support for Transformations - outer frame
 basegfx::B2DHomMatrix SwNoTextFrame::getFrameAreaTransformation() const
 {
-    if(!getLocalFrameAreaTransformation().isIdentity())
+    if(isTransformableSwFrame())
     {
         // use pre-created transformation
-        return getLocalFrameAreaTransformation();
+        return getTransformableSwFrame()->getLocalFrameAreaTransformation();
     }
 
     // call parent
@@ -568,10 +590,10 @@ basegfx::B2DHomMatrix SwNoTextFrame::getFrameAreaTransformation() const
 
 basegfx::B2DHomMatrix SwNoTextFrame::getFramePrintAreaTransformation() const
 {
-    if(!getLocalFramePrintAreaTransformation().isIdentity())
+    if(isTransformableSwFrame())
     {
         // use pre-created transformation
-        return getLocalFramePrintAreaTransformation();
+        return getTransformableSwFrame()->getLocalFramePrintAreaTransformation();
     }
 
     // call parent
@@ -586,14 +608,14 @@ void SwNoTextFrame::transform_translate(const Point& rOffset)
     SwContentFrame::transform_translate(rOffset);
 
     // check if the Transformations need to be adapted
-    if(isTransformationUsed())
+    if(isTransformableSwFrame())
     {
         const basegfx::B2DHomMatrix aTransform(
             basegfx::utils::createTranslateB2DHomMatrix(
                 rOffset.X(), rOffset.Y()));
 
         // transform using TransformableSwFrame
-        doTransform(aTransform);
+        getTransformableSwFrame()->doTransform(aTransform);
     }
 }
 
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index c388d80a0c0b..429ff26b25e8 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -30,7 +30,7 @@ double getFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
 
 // Base class for those Flys that can "move freely" or better that are not
 // bound in Content.
-class SwFlyFreeFrame : public SwFlyFrame, public TransformableSwFrame
+class SwFlyFreeFrame : public SwFlyFrame
 {
 private:
     // #i34753# - flag for at-page anchored Writer fly frames
@@ -43,6 +43,9 @@ private:
 
     SwRect maUnclippedFrame;
 
+    // RotateFlyFrame3 add TransformableSwFrame
+    std::unique_ptr< TransformableSwFrame >     mpTransformableSwFrame;
+
     void CheckClip( const SwFormatFrameSize &rSz );  //'Emergency' Clipping.
 
     /** determines, if direct environment of fly frame has 'auto' size
@@ -126,6 +129,11 @@ public:
     virtual bool IsFormatPossible() const override;
 
     // RotateFlyFrame3 - Support for Transformations
+    bool isTransformableSwFrame() const { return bool(mpTransformableSwFrame); }
+    TransformableSwFrame* getTransformableSwFrame() { return mpTransformableSwFrame.get(); }
+    const TransformableSwFrame* getTransformableSwFrame() const { return mpTransformableSwFrame.get(); }
+
+    // RotateFlyFrame3 - Support for Transformations
     virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const override;
     virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const override;
 
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 7cb12dadad1a..b8a2d7ab0370 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -220,54 +220,25 @@ public:
 class SW_DLLPUBLIC TransformableSwFrame
 {
 private:
+    // The SwFrameAreaDefinition to work on
+    SwFrameAreaDefinition&  mrSwFrameAreaDefinition;
+
     // FrameAreaTransformation and FramePrintAreaTransformation
     // here when more than translate/scale is used (e.g. rotation)
     basegfx::B2DHomMatrix   maFrameAreaTransformation;
     basegfx::B2DHomMatrix   maFramePrintAreaTransformation;
 
-    // helper method to create FrameAreaTransformations based on the
-    // curent FrameAreaDefinition
-    void createFrameAreaTransformations(
-        const SwFrameAreaDefinition& rSwFrameAreaDefinition,
-        double fRotation,
-        const basegfx::B2DPoint& rCenter);
-
-    // helper method to set FrameAreaDefinitions based on given
-    // transformations
-    void setFrameAreaDefinitionsToBoundRangesOfTransformations(
-        SwFrameAreaDefinition& rSwFrameAreaDefinition);
-
-protected:
-    // Full update of Transformations and BoundAreas:
-    // - Re-create Transformations based on SwRect(s) from the
-    //   given SwFrameAreaDefinition.
-    // - Based on that, create BoundRanges for the Transformations
-    //   and use as new SwRect(s) for the given SwFrameAreaDefinition.
-    void updateTransformationsAndFrameAreaDefinitions(
-        SwFrameAreaDefinition& rSwFrameAreaDefinition,
-        double fRotation,
-        const basegfx::B2DPoint& rCenter);
-
-    void setLocalFrameAreaTransformation(const basegfx::B2DHomMatrix& rNew)
-    {
-        maFrameAreaTransformation = rNew;
-    }
-
-    void setLocalFramePrintAreaTransformation(const basegfx::B2DHomMatrix& rNew)
-    {
-        maFramePrintAreaTransformation = rNew;
-    }
-
-    void resetLocalAreaTransformations()
-    {
-        maFrameAreaTransformation.identity();
-        maFramePrintAreaTransformation.identity();
-    }
+    // last saved versions of SwRect(s) from SwFrameAreaDefinition
+    SwRect                  maSavedFrameArea;
+    SwRect                  maSavedFramePrintArea;
 
 public:
-    TransformableSwFrame()
-    :   maFrameAreaTransformation(),
-        maFramePrintAreaTransformation()
+    TransformableSwFrame(SwFrameAreaDefinition& rSwFrameAreaDefinition)
+    :   mrSwFrameAreaDefinition(rSwFrameAreaDefinition),
+        maFrameAreaTransformation(),
+        maFramePrintAreaTransformation(),
+        maSavedFrameArea(),
+        maSavedFramePrintArea()
     {
     }
 
@@ -282,27 +253,23 @@ public:
         return maFramePrintAreaTransformation;
     }
 
-    // This method allows to reset the SwRect(s) in the
-    // given SwFrameAreaDefinition which are already apapted to
-    // Transformation and thus have a changed BoundArea back to
-    // the untransformed state. Only the SwRect(s) are changed
-    // back, not the transformations. As expected from using
-    // Transformations, these contain all the necessary
-    // information
-    void resetAreaDefinitionsToUntransformed(
-        SwFrameAreaDefinition& rSwFrameAreaDefinition);
+    // Helper method to re-create FrameAreaTransformations based on the
+    // curent FrameAreaDefinition, 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 resetAreaDefinitionsToTransformed).
+    // Only the SwRect(s) are changed back, not the transformations.
+    void resetAreaDefinitionsToUntransformed();
 
     // Re-Creates the SwRect(s) as BoundAreas based on the current
-    // Transformations, useful to set back the SwRect(s) to Transformed
-    // state when itz was necessary to reset them temporarily (see above)
-    void resetAreaDefinitionsToTransformed(
-        SwFrameAreaDefinition& rSwFrameAreaDefinition);
-
-    // check if used
-    bool isTransformationUsed() const
-    {
-        return !maFrameAreaTransformation.isIdentity() || !maFramePrintAreaTransformation.isIdentity();
-    }
+    // set Transformations, also saves the last SwRect(s) to the save
+    // values.
+    void resetAreaDefinitionsToTransformed();
 
     // transform by given B2DHomMatrix
     void doTransform(const basegfx::B2DHomMatrix aTransform);
diff --git a/sw/source/core/inc/notxtfrm.hxx b/sw/source/core/inc/notxtfrm.hxx
index 0054078890a4..6144b32e58eb 100644
--- a/sw/source/core/inc/notxtfrm.hxx
+++ b/sw/source/core/inc/notxtfrm.hxx
@@ -26,7 +26,7 @@ class OutputDevice;
 class SwBorderAttrs;
 struct SwCursorMoveState;
 
-class SwNoTextFrame: public SwContentFrame, public TransformableSwFrame
+class SwNoTextFrame: public SwContentFrame
 {
 private:
     friend void FrameFinit();
@@ -38,6 +38,9 @@ private:
     virtual void DestroyImpl() override;
     virtual ~SwNoTextFrame() override;
 
+    // RotateFlyFrame3 add TransformableSwFrame
+    std::unique_ptr< TransformableSwFrame >     mpTransformableSwFrame;
+
     // RotateFlyFrame3 - Support for inner frame of a SwGrfNode.
     // Only for local data extraction. To uniquely access information
     // for local transformation, use getFrameArea(Print)Transformation.
@@ -66,6 +69,11 @@ public:
     bool HasAnimation()  const;
 
     // RotateFlyFrame3 - Support for Transformations
+    bool isTransformableSwFrame() const { return bool(mpTransformableSwFrame); }
+    TransformableSwFrame* getTransformableSwFrame() { return mpTransformableSwFrame.get(); }
+    const TransformableSwFrame* getTransformableSwFrame() const { return mpTransformableSwFrame.get(); }
+
+    // RotateFlyFrame3 - Support for Transformations
     virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const override;
     virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const override;
 
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
index 7a9aa676dfdc..10c519fea697 100644
--- a/sw/source/core/layout/flylay.cxx
+++ b/sw/source/core/layout/flylay.cxx
@@ -47,12 +47,13 @@ using namespace ::com::sun::star;
 
 SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch )
 :   SwFlyFrame( pFormat, pSib, pAnch ),
-    TransformableSwFrame(),
     // #i34753#
     mbNoMakePos( false ),
     // #i37068#
     mbNoMoveOnCheckClip( false ),
-    maUnclippedFrame( )
+    maUnclippedFrame(),
+    // RotateFlyFrame3
+    mpTransformableSwFrame()
 {
 }
 
@@ -154,6 +155,21 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
     int nLoopControlRuns = 0;
     const int nLoopControlMax = 10;
 
+    // RotateFlyFrame3 - outer frame
+    const double fRotation(getFrameRotation());
+    const bool bRotated(!basegfx::fTools::equalZero(fRotation));
+
+    if(bRotated)
+    {
+        // Re-layout may be partially (see all isFrameAreaDefinitionValid() flags),
+        // so resetting the local SwFrame(s) in the local SwFrameAreaDefinition is
+        // needed. Reset to BoundAreas will be done below automatically
+        if(isTransformableSwFrame())
+        {
+            getTransformableSwFrame()->resetAreaDefinitionsToUntransformed();
+        }
+    }
+
     while ( !isFrameAreaPositionValid() || !isFrameAreaSizeValid() || !isFramePrintAreaValid() || m_bFormatHeightOnly || !m_bValidContentPos )
     {
         SwRectFnSet aRectFnSet(this);
@@ -233,30 +249,27 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
     // RotateFlyFrame3 - outer frame
     // Do not refresh transforms/Areas self here, this will be done
     // when inner and outer frame are layouted, in SwNoTextFrame::MakeAll
-    const double fRotation(getFrameRotation());
-    const bool bRotated(!basegfx::fTools::equalZero(fRotation));
-
-    if(!bRotated)
-    {
-        // reset transformations to show that they are not used
-        resetLocalAreaTransformations();
-    }
-    else
+    if(bRotated)
     {
         // RotateFlyFrame3: Safe changes locally
-        const bool bMeValid(isFrameAreaDefinitionValid());
+        // get center from outer frame (layout frame) to be on the safe side
+        const Point aCenter(getFrameArea().Center());
+        const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
 
-        if(bMeValid)
+        if(!mpTransformableSwFrame)
         {
-            // get center from outer frame (layout frame) to be on the safe side
-            const Point aCenter(getFrameArea().Center());
-            const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
-
-            updateTransformationsAndFrameAreaDefinitions(
-                *this,
-                fRotation,
-                aB2DCenter);
+            mpTransformableSwFrame.reset(new TransformableSwFrame(*this));
         }
+
+        getTransformableSwFrame()->createFrameAreaTransformations(
+            fRotation,
+            aB2DCenter);
+        getTransformableSwFrame()->resetAreaDefinitionsToTransformed();
+    }
+    else
+    {
+        // reset transformations to show that they are not used
+        mpTransformableSwFrame.reset();
     }
 
     Unlock();
@@ -273,10 +286,10 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
 // RotateFlyFrame3 - Support for Transformations - outer frame
 basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
 {
-    if(!getLocalFrameAreaTransformation().isIdentity())
+    if(isTransformableSwFrame())
     {
         // use pre-created transformation
-        return getLocalFrameAreaTransformation();
+        return getTransformableSwFrame()->getLocalFrameAreaTransformation();
     }
 
     // call parent
@@ -285,10 +298,10 @@ basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
 
 basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const
 {
-    if(!getLocalFramePrintAreaTransformation().isIdentity())
+    if(isTransformableSwFrame())
     {
         // use pre-created transformation
-        return getLocalFramePrintAreaTransformation();
+        return getTransformableSwFrame()->getLocalFramePrintAreaTransformation();
     }
 
     // call parent
@@ -303,14 +316,14 @@ void SwFlyFreeFrame::transform_translate(const Point& rOffset)
     SwFlyFrame::transform_translate(rOffset);
 
     // check if the Transformations need to be adapted
-    if(isTransformationUsed())
+    if(isTransformableSwFrame())
     {
         const basegfx::B2DHomMatrix aTransform(
             basegfx::utils::createTranslateB2DHomMatrix(
                 rOffset.X(), rOffset.Y()));
 
         // transform using TransformableSwFrame
-        doTransform(aTransform);
+        getTransformableSwFrame()->doTransform(aTransform);
     }
 }
 
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index a67a70d46c76..4cd9245eb2f0 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -147,33 +147,26 @@ void SwFrameAreaDefinition::transform_translate(const Point& rOffset)
 }
 
 void TransformableSwFrame::createFrameAreaTransformations(
-    const SwFrameAreaDefinition& rSwFrameAreaDefinition,
     double fRotation,
     const basegfx::B2DPoint& rCenter)
 {
-    // save Transformations to rFrameAreaTransformation and
-    // rFramePrintAreaTransformation. Do not forget that PrintArea
-    // is *relative* to FrameArea
     const basegfx::B2DHomMatrix aRotateAroundCenter(
         basegfx::utils::createRotateAroundPoint(
             rCenter.getX(),
             rCenter.getY(),
             fRotation));
-    const SwRect& rFrameArea(rSwFrameAreaDefinition.getFrameArea());
-    const SwRect& rFramePrintArea(rSwFrameAreaDefinition.getFramePrintArea());
-
-    setLocalFrameAreaTransformation(
-        aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
-            rFrameArea.Width(), rFrameArea.Height(),
-            rFrameArea.Left(), rFrameArea.Top()));
-    setLocalFramePrintAreaTransformation(
-        aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
-            rFramePrintArea.Width(), rFramePrintArea.Height(),
-            rFramePrintArea.Left() + rFrameArea.Left(), rFramePrintArea.Top() + rFrameArea.Top()));
+    const SwRect& rFrameArea(mrSwFrameAreaDefinition.getFrameArea());
+    const SwRect& rFramePrintArea(mrSwFrameAreaDefinition.getFramePrintArea());
+
+    maFrameAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
+        rFrameArea.Width(), rFrameArea.Height(),
+        rFrameArea.Left(), rFrameArea.Top());
+    maFramePrintAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
+        rFramePrintArea.Width(), rFramePrintArea.Height(),
+        rFramePrintArea.Left() + rFrameArea.Left(), rFramePrintArea.Top() + rFrameArea.Top());
 }
 
-void TransformableSwFrame::setFrameAreaDefinitionsToBoundRangesOfTransformations(
-    SwFrameAreaDefinition& rSwFrameAreaDefinition)
+void TransformableSwFrame::resetAreaDefinitionsToTransformed()
 {
     if(!getLocalFrameAreaTransformation().isIdentity())
     {
@@ -183,9 +176,10 @@ void TransformableSwFrame::setFrameAreaDefinitionsToBoundRangesOfTransformations
             basegfx::fround(aRangeFrameArea.getMinX()), basegfx::fround(aRangeFrameArea.getMinY()),
             basegfx::fround(aRangeFrameArea.getWidth()), basegfx::fround(aRangeFrameArea.getHeight()));
 
-        if(aNewFrm != rSwFrameAreaDefinition.getFrameArea())
+        if(aNewFrm != mrSwFrameAreaDefinition.getFrameArea())
         {
-            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(rSwFrameAreaDefinition);
+            maSavedFrameArea = mrSwFrameAreaDefinition.getFrameArea();
+            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
             aFrm.setSwRect(aNewFrm);
         }
     }
@@ -195,83 +189,40 @@ void TransformableSwFrame::setFrameAreaDefinitionsToBoundRangesOfTransformations
         basegfx::B2DRange aRangeFramePrintArea(0.0, 0.0, 1.0, 1.0);
         aRangeFramePrintArea.transform(getLocalFramePrintAreaTransformation());
         const SwRect aNewPrt(
-            basegfx::fround(aRangeFramePrintArea.getMinX()) - rSwFrameAreaDefinition.getFrameArea().Left(),
-            basegfx::fround(aRangeFramePrintArea.getMinY()) - rSwFrameAreaDefinition.getFrameArea().Top(),
+            basegfx::fround(aRangeFramePrintArea.getMinX()) - mrSwFrameAreaDefinition.getFrameArea().Left(),
+            basegfx::fround(aRangeFramePrintArea.getMinY()) - mrSwFrameAreaDefinition.getFrameArea().Top(),
             basegfx::fround(aRangeFramePrintArea.getWidth()),
             basegfx::fround(aRangeFramePrintArea.getHeight()));
 
-        if(aNewPrt != rSwFrameAreaDefinition.getFramePrintArea())
+        if(aNewPrt != mrSwFrameAreaDefinition.getFramePrintArea())
         {
-            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(rSwFrameAreaDefinition);
+            maSavedFramePrintArea = mrSwFrameAreaDefinition.getFramePrintArea();
+            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
             aPrt.setSwRect(aNewPrt);
         }
     }
 }
 
-void TransformableSwFrame::updateTransformationsAndFrameAreaDefinitions(
-    SwFrameAreaDefinition& rSwFrameAreaDefinition,
-    double fRotation,
-    const basegfx::B2DPoint& rCenter)
+void TransformableSwFrame::resetAreaDefinitionsToUntransformed()
 {
-    createFrameAreaTransformations(
-        rSwFrameAreaDefinition,
-        fRotation,
-        rCenter);
+    // 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
 
-    setFrameAreaDefinitionsToBoundRangesOfTransformations(
-        rSwFrameAreaDefinition);
-}
-
-void TransformableSwFrame::resetAreaDefinitionsToUntransformed(
-    SwFrameAreaDefinition& rSwFrameAreaDefinition)
-{
-    // calculate center of object
-    basegfx::B2DPoint aCenter(getLocalFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
-
-    if(!getLocalFrameAreaTransformation().isIdentity())
+    if(!getLocalFrameAreaTransformation().isIdentity() && maSavedFrameArea != mrSwFrameAreaDefinition.getFrameArea())
     {
-        basegfx::B2DTuple aScale, aTranslate;
-        double fRotate(0.0), fShearX(0.0);
-        getLocalFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
-        const SwRect aNewFrm(
-            basegfx::fround(aCenter.getX() - (0.5 * aScale.getX())),
-            basegfx::fround(aCenter.getY() - (0.5 * aScale.getY())),
-            basegfx::fround(aScale.getX()),
-            basegfx::fround(aScale.getY()));
-
-        if(aNewFrm != rSwFrameAreaDefinition.getFrameArea())
-        {
-            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(rSwFrameAreaDefinition);
-            aFrm.setSwRect(aNewFrm);
-        }
+        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(mrSwFrameAreaDefinition);
+        aFrm.setSwRect(maSavedFrameArea);
     }
 
-    if(!getLocalFramePrintAreaTransformation().isIdentity())
+    if(!getLocalFramePrintAreaTransformation().isIdentity() && maSavedFramePrintArea != mrSwFrameAreaDefinition.getFramePrintArea())
     {
-        basegfx::B2DTuple aScale, aTranslate;
-        double fRotate(0.0), fShearX(0.0);
-        getLocalFramePrintAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
-        const SwRect aNewPrt(
-            basegfx::fround(aCenter.getX() - (0.5 * aScale.getX())) - rSwFrameAreaDefinition.getFrameArea().Left(),
-            basegfx::fround(aCenter.getY() - (0.5 * aScale.getY())) - rSwFrameAreaDefinition.getFrameArea().Top(),
-            basegfx::fround(aScale.getX()),
-            basegfx::fround(aScale.getY()));
-
-        if(aNewPrt != rSwFrameAreaDefinition.getFramePrintArea())
-        {
-            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(rSwFrameAreaDefinition);
-            aPrt.setSwRect(aNewPrt);
-        }
+        SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(mrSwFrameAreaDefinition);
+        aPrt.setSwRect(maSavedFramePrintArea);
     }
 }
 
-void TransformableSwFrame::resetAreaDefinitionsToTransformed(
-    SwFrameAreaDefinition& rSwFrameAreaDefinition)
-{
-    setFrameAreaDefinitionsToBoundRangesOfTransformations(
-        rSwFrameAreaDefinition);
-}
-
 // transform by given B2DHomMatrix
 void TransformableSwFrame::doTransform(const basegfx::B2DHomMatrix aTransform)
 {
commit 7b70e6a57fcbc4b73da7c75105ec58a6777d610f
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Nov 9 11:35:09 2017 +0100

    RotateFlyFrame3: Added basic transformation support
    
    In lcl_MoveAllLowers SwFrame(s) were directly modified,
    not even by calling any member method what makes it hard to
    react on changes to geometric definition(s). Added logic
    to Transform a SwFrame, currently basic by using e.g.
    SwFrame::Ltransform_translate, may be later unified to
    general Transformation usage with a homogen Matrix
    
    Change-Id: I7582fbd1472e12e481adacedda2e65cc0c282eac

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index b4fb5485d02e..897e9f6d1121 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -578,6 +578,25 @@ basegfx::B2DHomMatrix SwNoTextFrame::getFramePrintAreaTransformation() const
     return SwContentFrame::getFramePrintAreaTransformation();
 }
 
+// RotateFlyFrame3 - Support for Transformations
+void SwNoTextFrame::transform_translate(const Point& rOffset)
+{
+    // call parent - this will do the basic transform for SwRect(s)
+    // in the SwFrameAreaDefinition
+    SwContentFrame::transform_translate(rOffset);
+
+    // check if the Transformations need to be adapted
+    if(isTransformationUsed())
+    {
+        const basegfx::B2DHomMatrix aTransform(
+            basegfx::utils::createTranslateB2DHomMatrix(
+                rOffset.X(), rOffset.Y()));
+
+        // transform using TransformableSwFrame
+        doTransform(aTransform);
+    }
+}
+
 // RotateFlyFrame3 - inner frame
 // Check if we contain a SwGrfNode and get possible rotation from it
 double SwNoTextFrame::getFrameRotation() const
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index b4f66f9d22d3..c388d80a0c0b 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -128,6 +128,9 @@ public:
     // RotateFlyFrame3 - Support for Transformations
     virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const override;
     virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const override;
+
+    // RotateFlyFrame3 - Support for Transformations
+    virtual void transform_translate(const Point& rOffset) override;
 };
 
 // Flys that are bound to LayoutFrames and not to Content
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index 2d0a1c321372..7cb12dadad1a 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -205,6 +205,13 @@ public:
     // SwFrame of a SwFlyFrame)
     virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const;
     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
+    virtual void transform_translate(const Point& rOffset);
 };
 
 /// RotateFlyFrame3: Helper class when you want to make your SwFrame derivate
@@ -290,6 +297,15 @@ public:
     // state when itz was necessary to reset them temporarily (see above)
     void resetAreaDefinitionsToTransformed(
         SwFrameAreaDefinition& rSwFrameAreaDefinition);
+
+    // check if used
+    bool isTransformationUsed() const
+    {
+        return !maFrameAreaTransformation.isIdentity() || !maFramePrintAreaTransformation.isIdentity();
+    }
+
+    // transform by given B2DHomMatrix
+    void doTransform(const basegfx::B2DHomMatrix aTransform);
 };
 
 /**
diff --git a/sw/source/core/inc/notxtfrm.hxx b/sw/source/core/inc/notxtfrm.hxx
index 43f020496599..0054078890a4 100644
--- a/sw/source/core/inc/notxtfrm.hxx
+++ b/sw/source/core/inc/notxtfrm.hxx
@@ -68,6 +68,9 @@ public:
     // RotateFlyFrame3 - Support for Transformations
     virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const override;
     virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const override;
+
+    // RotateFlyFrame3 - Support for Transformations
+    virtual void transform_translate(const Point& rOffset) override;
 };
 
 #endif
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
index 2c8cc422dd25..7a9aa676dfdc 100644
--- a/sw/source/core/layout/flylay.cxx
+++ b/sw/source/core/layout/flylay.cxx
@@ -41,6 +41,7 @@
 #include <viewimp.hxx>
 #include <IDocumentSettingAccess.hxx>
 #include <IDocumentDrawModelAccess.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
 
 using namespace ::com::sun::star;
 
@@ -294,6 +295,25 @@ basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const
     return SwFlyFrame::getFramePrintAreaTransformation();
 }
 
+// RotateFlyFrame3 - Support for Transformations
+void SwFlyFreeFrame::transform_translate(const Point& rOffset)
+{
+    // call parent - this will do the basic transform for SwRect(s)
+    // in the SwFrameAreaDefinition
+    SwFlyFrame::transform_translate(rOffset);
+
+    // check if the Transformations need to be adapted
+    if(isTransformationUsed())
+    {
+        const basegfx::B2DHomMatrix aTransform(
+            basegfx::utils::createTranslateB2DHomMatrix(
+                rOffset.X(), rOffset.Y()));
+
+        // transform using TransformableSwFrame
+        doTransform(aTransform);
+    }
+}
+
 // RotateFlyFrame3 - outer frame
 double getFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame)
 {
diff --git a/sw/source/core/layout/pagechg.cxx b/sw/source/core/layout/pagechg.cxx
index 716642b03fa5..72f86fc8fd69 100644
--- a/sw/source/core/layout/pagechg.cxx
+++ b/sw/source/core/layout/pagechg.cxx
@@ -1927,19 +1927,9 @@ static void lcl_MoveAllLowers( SwFrame* pFrame, const Point& rOffset )
     const SwRect aFrame( pFrame->getFrameArea() );
 
     // first move the current frame
-    {
-        SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*pFrame);
-
-        if (aFrm.Pos().X() != FAR_AWAY)
-        {
-            aFrm.Pos().X() += rOffset.X();
-        }
-
-        if (aFrm.Pos().Y() != FAR_AWAY)
-        {
-            aFrm.Pos().Y() += rOffset.Y();
-        }
-    }
+    // RotateFlyFrame3: moved to transform_translate instead of
+    // direct modification to allow the SwFrame evtl. needed own reactions
+    pFrame->transform_translate(rOffset);
 
     // Don't forget accessibility:
     if( pFrame->IsAccessibleFrame() )
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 972083bd273d..a67a70d46c76 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -129,6 +129,23 @@ basegfx::B2DHomMatrix SwFrameAreaDefinition::getFramePrintAreaTransformation() c
         rFramePrintArea.Top() + rFrameArea.Top());
 }
 
+void SwFrameAreaDefinition::transform_translate(const Point& rOffset)
+{
+    // RotateFlyFrame3: default is to change the FrameArea, FramePrintArea needs no
+    // change since it is relative to FrameArea
+    SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(*this);
+
+    if (aFrm.Pos().X() != FAR_AWAY)
+    {
+        aFrm.Pos().X() += rOffset.X();
+    }
+
+    if (aFrm.Pos().Y() != FAR_AWAY)
+    {
+        aFrm.Pos().Y() += rOffset.Y();
+    }
+}
+
 void TransformableSwFrame::createFrameAreaTransformations(
     const SwFrameAreaDefinition& rSwFrameAreaDefinition,
     double fRotation,
@@ -255,6 +272,23 @@ void TransformableSwFrame::resetAreaDefinitionsToTransformed(
         rSwFrameAreaDefinition);
 }
 
+// transform by given B2DHomMatrix
+void TransformableSwFrame::doTransform(const basegfx::B2DHomMatrix aTransform)
+{
+    if(!aTransform.isIdentity())
+    {
+        if(!maFrameAreaTransformation.isIdentity())
+        {
+            maFrameAreaTransformation *= aTransform;
+        }
+
+        if(!maFramePrintAreaTransformation.isIdentity())
+        {
+            maFramePrintAreaTransformation *= aTransform;
+        }
+    }
+}
+
 SwFrame::SwFrame( SwModify *pMod, SwFrame* pSib )
 :   SwFrameAreaDefinition(),
     SwClient( pMod ),
commit bc4432846a8142b5e5d559eff392c28c888260ba
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Wed Nov 8 14:00:57 2017 +0100

    RotateFlyFrame3: Isolated functionality and automations
    
    Isolated tooling stuff for SwFrames that support Transformations
    to TransformableSwFrame, adapted all usages. Developed functionality
    to reset temporarily the already adapted SwFrame of the outer frame
    to non-rotated to mate the layouting work. Made the outer frame
    being layouted always first.
    
    Change-Id: Ia60a971b8eaa28859d0f2a5243eabf68fe949846

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 1accccb8e492..b4fb5485d02e 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -144,8 +144,7 @@ static void lcl_PaintReplacement( const SwRect &rRect, const OUString &rText,
 
 SwNoTextFrame::SwNoTextFrame(SwNoTextNode * const pNode, SwFrame* pSib )
 :   SwContentFrame( pNode, pSib ),
-    maFrameAreaTransformation(),
-    maFramePrintAreaTransformation()
+    TransformableSwFrame()
 {
     mnFrameType = SwFrameType::NoTxt;
 }
@@ -472,11 +471,28 @@ const Size& SwNoTextFrame::GetSize() const
 
 void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
 {
-    if(GetUpper() && !GetUpper()->isFrameAreaDefinitionValid())
+    // 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())
+    {
+        // RotateFlyFrame3: outer frame *needs* to be layouted first, force this by calling
+        // it's ::Calc directly
+        pUpperFly->Calc(pRenderContext);
+    }
+
+    if(bRotated && pUpperFly)
     {
-        // outer frame *needs* to be layouted first, force this by calling
-        // ::Calc directly
-        GetUpper()->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
+        pUpperFly->resetAreaDefinitionsToUntransformed(*pUpperFly);
     }
 
     SwContentNotify aNotify( this );
@@ -504,66 +520,46 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
 
     // RotateFlyFrame3 - inner frame
     // After the unrotated layout is finished, apply possible set rotation to it
-    const double fRotation(getFrameRotation());
-
-    if(basegfx::fTools::equalZero(fRotation))
+    if(!bRotated)
     {
         // reset transformations to show that they are not used
-        maFrameAreaTransformation.identity();
-        maFramePrintAreaTransformation.identity();
+        resetLocalAreaTransformations();
     }
     else
     {
         const bool bMeValid(isFrameAreaDefinitionValid());
-        const bool bUpperValid(!GetUpper() || GetUpper()->isFrameAreaDefinitionValid());
 
-        if(bMeValid && bUpperValid)
+        if(pUpperFly)
+        {
+            // restore outer frame back to Transformed state, that means
+            // set the SwFrameAreaDefinition(s) back to BoundAreas of
+            // 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(bMeValid)
         {
             // 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());
 
-            updateTransformationsAndAreas(
+            updateTransformationsAndFrameAreaDefinitions(
+                *this,
                 fRotation,
                 aB2DCenter);
-
-            if(GetUpper())
-            {
-                SwFlyFreeFrame *pFly = dynamic_cast< SwFlyFreeFrame* >(GetUpper());
-
-                if(pFly)
-                {
-                    pFly->updateTransformationsAndAreas(
-                        fRotation,
-                        aB2DCenter);
-                }
-            }
         }
     }
 }
 
-void SwNoTextFrame::updateTransformationsAndAreas(
-    double fRotation,
-    const basegfx::B2DPoint& rCenter)
-{
-    createFrameAreaTransformations(
-        maFrameAreaTransformation,
-        maFramePrintAreaTransformation,
-        fRotation,
-        rCenter);
-
-    setFrameAreaDefinitionsToBoundRangesOfTransformations(
-        maFrameAreaTransformation,
-        maFramePrintAreaTransformation);
-}
-
 // RotateFlyFrame3 - Support for Transformations - outer frame
 basegfx::B2DHomMatrix SwNoTextFrame::getFrameAreaTransformation() const
 {
-    if(!maFrameAreaTransformation.isIdentity())
+    if(!getLocalFrameAreaTransformation().isIdentity())
     {
         // use pre-created transformation
-        return maFrameAreaTransformation;
+        return getLocalFrameAreaTransformation();
     }
 
     // call parent
@@ -572,10 +568,10 @@ basegfx::B2DHomMatrix SwNoTextFrame::getFrameAreaTransformation() const
 
 basegfx::B2DHomMatrix SwNoTextFrame::getFramePrintAreaTransformation() const
 {
-    if(!maFramePrintAreaTransformation.isIdentity())
+    if(!getLocalFramePrintAreaTransformation().isIdentity())
     {
         // use pre-created transformation
-        return maFramePrintAreaTransformation;
+        return getLocalFramePrintAreaTransformation();
     }
 
     // call parent
diff --git a/sw/source/core/inc/flyfrms.hxx b/sw/source/core/inc/flyfrms.hxx
index e202c9733d88..b4f66f9d22d3 100644
--- a/sw/source/core/inc/flyfrms.hxx
+++ b/sw/source/core/inc/flyfrms.hxx
@@ -26,9 +26,11 @@
 // #i28701#
 class SwFlyAtContentFrame;
 
+double getFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame);
+
 // Base class for those Flys that can "move freely" or better that are not
 // bound in Content.
-class SwFlyFreeFrame : public SwFlyFrame
+class SwFlyFreeFrame : public SwFlyFrame, public TransformableSwFrame
 {
 private:
     // #i34753# - flag for at-page anchored Writer fly frames
@@ -41,12 +43,6 @@ private:
 
     SwRect maUnclippedFrame;
 
-    // RotateFlyFrame3 - Support for Transformations, hold
-    // FrameAreaTransformation and FramePrintAreaTransformation
-    // here when rotation is used
-    basegfx::B2DHomMatrix   maFrameAreaTransformation;
-    basegfx::B2DHomMatrix   maFramePrintAreaTransformation;
-
     void CheckClip( const SwFormatFrameSize &rSz );  //'Emergency' Clipping.
 
     /** determines, if direct environment of fly frame has 'auto' size
@@ -61,6 +57,11 @@ private:
     */
     bool HasEnvironmentAutoSize() const;
 
+    // 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;
+
 protected:
     // #i28701# - new friend class <SwFlyNotify> for access to
     // method <NotifyBackground>
@@ -124,17 +125,9 @@ public:
     */
     virtual bool IsFormatPossible() const override;
 
-    // RotateFlyFrame3 - Support for Transformations for outer Frame of a SwGrfNode
-    basegfx::B2DHomMatrix getFrameAreaTransformation() const;
-    basegfx::B2DHomMatrix getFramePrintAreaTransformation() const;
-    void updateTransformationsAndAreas(
-        double fRotation,
-        const basegfx::B2DPoint& rCenter);
-
-    // 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;
+    // RotateFlyFrame3 - Support for Transformations
+    virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const override;
+    virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const override;
 };
 
 // Flys that are bound to LayoutFrames and not to Content
diff --git a/sw/source/core/inc/frame.hxx b/sw/source/core/inc/frame.hxx
index d02426976204..2d0a1c321372 100644
--- a/sw/source/core/inc/frame.hxx
+++ b/sw/source/core/inc/frame.hxx
@@ -144,20 +144,6 @@ protected:
     void setFrameAreaSizeValid(bool bNew);
     void setFramePrintAreaValid(bool bNew);
 
-    // helper method to create FrameAreaTransformations based on the
-    // curent FrameAreaDefinition
-    void createFrameAreaTransformations(
-        basegfx::B2DHomMatrix& rFrameAreaTransformation,
-        basegfx::B2DHomMatrix& rFramePrintAreaTransformation,
-        double fRotation,
-        const basegfx::B2DPoint& rCenter) const;
-
-    // helper method to set FrameAreaDefinitions based on given
-    // transformations
-    void setFrameAreaDefinitionsToBoundRangesOfTransformations(
-        const basegfx::B2DHomMatrix& rFrameAreaTransformation,
-        const basegfx::B2DHomMatrix& rFramePrintAreaTransformation);
-
 public:
     SwFrameAreaDefinition();
 
@@ -208,6 +194,102 @@ public:
         ~FramePrintAreaWriteAccess();
         void setSwRect(const SwRect& rNew) { *reinterpret_cast< SwRect* >(this) = rNew; }
     };
+
+    // RotateFlyFrame3 - Support for Transformations
+    // Hand out the Transformations for the current FrameAreaDefinition
+    // for the FrameArea and FramePrintArea.
+    // FramePrintArea is not relative to FrameArea in this
+    // transformation representation (to make it easier to use and understand).
+    // There is no 'set' method since SwFrame is a layout obejct. For
+    // some cases rotation will be included (used for SwGrfNode in inner
+    // SwFrame of a SwFlyFrame)
+    virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const;
+    virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const;
+};
+
+/// 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
+class SW_DLLPUBLIC TransformableSwFrame
+{
+private:
+    // FrameAreaTransformation and FramePrintAreaTransformation
+    // here when more than translate/scale is used (e.g. rotation)
+    basegfx::B2DHomMatrix   maFrameAreaTransformation;
+    basegfx::B2DHomMatrix   maFramePrintAreaTransformation;
+
+    // helper method to create FrameAreaTransformations based on the
+    // curent FrameAreaDefinition
+    void createFrameAreaTransformations(
+        const SwFrameAreaDefinition& rSwFrameAreaDefinition,
+        double fRotation,
+        const basegfx::B2DPoint& rCenter);
+
+    // helper method to set FrameAreaDefinitions based on given
+    // transformations
+    void setFrameAreaDefinitionsToBoundRangesOfTransformations(
+        SwFrameAreaDefinition& rSwFrameAreaDefinition);
+
+protected:
+    // Full update of Transformations and BoundAreas:
+    // - Re-create Transformations based on SwRect(s) from the
+    //   given SwFrameAreaDefinition.
+    // - Based on that, create BoundRanges for the Transformations
+    //   and use as new SwRect(s) for the given SwFrameAreaDefinition.
+    void updateTransformationsAndFrameAreaDefinitions(
+        SwFrameAreaDefinition& rSwFrameAreaDefinition,
+        double fRotation,
+        const basegfx::B2DPoint& rCenter);
+
+    void setLocalFrameAreaTransformation(const basegfx::B2DHomMatrix& rNew)
+    {
+        maFrameAreaTransformation = rNew;
+    }
+
+    void setLocalFramePrintAreaTransformation(const basegfx::B2DHomMatrix& rNew)
+    {
+        maFramePrintAreaTransformation = rNew;
+    }
+
+    void resetLocalAreaTransformations()
+    {
+        maFrameAreaTransformation.identity();
+        maFramePrintAreaTransformation.identity();
+    }
+
+public:
+    TransformableSwFrame()
+    :   maFrameAreaTransformation(),
+        maFramePrintAreaTransformation()
+    {
+    }
+
+    // Support for Transformations for inner frame of a SwGrfNode
+    const basegfx::B2DHomMatrix& getLocalFrameAreaTransformation() const
+    {
+        return maFrameAreaTransformation;
+    }
+
+    const basegfx::B2DHomMatrix& getLocalFramePrintAreaTransformation() const
+    {
+        return maFramePrintAreaTransformation;
+    }
+
+    // This method allows to reset the SwRect(s) in the
+    // given SwFrameAreaDefinition which are already apapted to
+    // Transformation and thus have a changed BoundArea back to
+    // the untransformed state. Only the SwRect(s) are changed
+    // back, not the transformations. As expected from using
+    // Transformations, these contain all the necessary
+    // information
+    void resetAreaDefinitionsToUntransformed(
+        SwFrameAreaDefinition& rSwFrameAreaDefinition);
+
+    // Re-Creates the SwRect(s) as BoundAreas based on the current
+    // Transformations, useful to set back the SwRect(s) to Transformed
+    // state when itz was necessary to reset them temporarily (see above)
+    void resetAreaDefinitionsToTransformed(
+        SwFrameAreaDefinition& rSwFrameAreaDefinition);
 };
 
 /**
@@ -834,17 +916,6 @@ public:
     virtual void dumpAsXmlAttributes(xmlTextWriterPtr writer) const;
     void dumpChildrenAsXml(xmlTextWriterPtr writer) const;
     bool IsCollapse() const;
-
-    // RotateFlyFrame3 - Support for Transformations
-    // Hand out the Transformations for the current FrameAreaDefinition
-    // for the FrameArea and FramePrintArea.
-    // FramePrintArea is not relative to FrameArea in this
-    // transformation representation (to make it easier to use and understand).
-    // There is no 'set' method since SwFrame is a layout obejct. For
-    // some cases rotation will be included (used for SwGrfNode in inner
-    // SwFrame of a SwFlyFrame)
-    basegfx::B2DHomMatrix getFrameAreaTransformation() const;
-    basegfx::B2DHomMatrix getFramePrintAreaTransformation() const;
 };
 
 inline bool SwFrame::IsInDocBody() const
diff --git a/sw/source/core/inc/notxtfrm.hxx b/sw/source/core/inc/notxtfrm.hxx
index fa64a1be3214..43f020496599 100644
--- a/sw/source/core/inc/notxtfrm.hxx
+++ b/sw/source/core/inc/notxtfrm.hxx
@@ -26,17 +26,10 @@ class OutputDevice;
 class SwBorderAttrs;
 struct SwCursorMoveState;
 
-class SwNoTextFrame: public SwContentFrame
+class SwNoTextFrame: public SwContentFrame, public TransformableSwFrame
 {
 private:
     friend void FrameFinit();
-
-    // RotateFlyFrame3 - Support for Transformation, hold
-    // FrameAreaTransformation and FramePrintAreaTransformation
-    // here when rotation is used
-    basegfx::B2DHomMatrix   maFrameAreaTransformation;
-    basegfx::B2DHomMatrix   maFramePrintAreaTransformation;
-
     const Size& GetSize() const;
 
     void Format ( vcl::RenderContext* pRenderContext, const SwBorderAttrs *pAttrs = nullptr ) override;
@@ -45,9 +38,16 @@ private:
     virtual void DestroyImpl() override;
     virtual ~SwNoTextFrame() override;
 
+    // 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;
+
 protected:
     virtual void MakeAll(vcl::RenderContext* pRenderContext) override;
     virtual void Modify( const SfxPoolItem*, const SfxPoolItem* ) override;
+
 public:
     SwNoTextFrame( SwNoTextNode * const, SwFrame* );
 
@@ -65,17 +65,9 @@ public:
     void StopAnimation( OutputDevice* = nullptr ) const;
     bool HasAnimation()  const;
 
-    // RotateFlyFrame3 - Support for Transformations for inner frame of a SwGrfNode
-    basegfx::B2DHomMatrix getFrameAreaTransformation() const;
-    basegfx::B2DHomMatrix getFramePrintAreaTransformation() const;
-    void updateTransformationsAndAreas(
-        double fRotation,
-        const basegfx::B2DPoint& rCenter);
-
-    // RotateFlyFrame3 - Support for inner frame of a SwGrfNode.
-    // Only for local data extraction. To uniquely access information
-    // for local transformation, use getFrameArea(Print)Transformation.
-    double getFrameRotation() const;
+    // RotateFlyFrame3 - Support for Transformations
+    virtual basegfx::B2DHomMatrix getFrameAreaTransformation() const override;
+    virtual basegfx::B2DHomMatrix getFramePrintAreaTransformation() const override;
 };
 
 #endif
diff --git a/sw/source/core/layout/flylay.cxx b/sw/source/core/layout/flylay.cxx
index 0fdf70face11..2c8cc422dd25 100644
--- a/sw/source/core/layout/flylay.cxx
+++ b/sw/source/core/layout/flylay.cxx
@@ -46,14 +46,12 @@ using namespace ::com::sun::star;
 
 SwFlyFreeFrame::SwFlyFreeFrame( SwFlyFrameFormat *pFormat, SwFrame* pSib, SwFrame *pAnch )
 :   SwFlyFrame( pFormat, pSib, pAnch ),
+    TransformableSwFrame(),
     // #i34753#
     mbNoMakePos( false ),
     // #i37068#
     mbNoMoveOnCheckClip( false ),
-    maUnclippedFrame( ),
-    // RotateFlyFrame3
-    maFrameAreaTransformation(),
-    maFramePrintAreaTransformation()
+    maUnclippedFrame( )
 {
 }
 
@@ -110,9 +108,11 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
     }
 
     if ( !GetAnchorFrame() || IsLocked() || IsColLocked() )
+    {
         return;
+    }
 
-        // #i28701# - use new method <GetPageFrame()>
+    // #i28701# - use new method <GetPageFrame()>
     if( !GetPageFrame() && GetAnchorFrame() && GetAnchorFrame()->IsInFly() )
     {
         SwFlyFrame* pFly = AnchorFrame()->FindFlyFrame();
@@ -233,12 +233,29 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
     // Do not refresh transforms/Areas self here, this will be done
     // when inner and outer frame are layouted, in SwNoTextFrame::MakeAll
     const double fRotation(getFrameRotation());
+    const bool bRotated(!basegfx::fTools::equalZero(fRotation));
 
-    if(basegfx::fTools::equalZero(fRotation))
+    if(!bRotated)
     {
         // reset transformations to show that they are not used
-        maFrameAreaTransformation.identity();
-        maFramePrintAreaTransformation.identity();
+        resetLocalAreaTransformations();
+    }
+    else
+    {
+        // RotateFlyFrame3: Safe changes locally
+        const bool bMeValid(isFrameAreaDefinitionValid());
+
+        if(bMeValid)
+        {
+            // get center from outer frame (layout frame) to be on the safe side
+            const Point aCenter(getFrameArea().Center());
+            const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
+
+            updateTransformationsAndFrameAreaDefinitions(
+                *this,
+                fRotation,
+                aB2DCenter);
+        }
     }
 
     Unlock();
@@ -252,28 +269,13 @@ void SwFlyFreeFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
 #endif
 }
 
-void SwFlyFreeFrame::updateTransformationsAndAreas(
-    double fRotation,
-    const basegfx::B2DPoint& rCenter)
-{
-    createFrameAreaTransformations(
-        maFrameAreaTransformation,
-        maFramePrintAreaTransformation,
-        fRotation,
-        rCenter);
-
-    setFrameAreaDefinitionsToBoundRangesOfTransformations(
-        maFrameAreaTransformation,
-        maFramePrintAreaTransformation);
-}
-
 // RotateFlyFrame3 - Support for Transformations - outer frame
 basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
 {
-    if(!maFrameAreaTransformation.isIdentity())
+    if(!getLocalFrameAreaTransformation().isIdentity())
     {
         // use pre-created transformation
-        return maFrameAreaTransformation;
+        return getLocalFrameAreaTransformation();
     }
 
     // call parent
@@ -282,10 +284,10 @@ basegfx::B2DHomMatrix SwFlyFreeFrame::getFrameAreaTransformation() const
 
 basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const
 {
-    if(!maFramePrintAreaTransformation.isIdentity())
+    if(!getLocalFramePrintAreaTransformation().isIdentity())
     {
         // use pre-created transformation
-        return maFramePrintAreaTransformation;
+        return getLocalFramePrintAreaTransformation();
     }
 
     // call parent
@@ -293,6 +295,11 @@ basegfx::B2DHomMatrix SwFlyFreeFrame::getFramePrintAreaTransformation() const
 }
 
 // RotateFlyFrame3 - outer frame
+double getFrameRotation_from_SwNoTextFrame(const SwNoTextFrame& rNoTextFrame)
+{
+    return rNoTextFrame.getFrameRotation();
+}
+
 double SwFlyFreeFrame::getFrameRotation() const
 {
     // SwLayoutFrame::Lower() != SwFrame::GetLower(), but SwFrame::GetLower()
@@ -301,7 +308,7 @@ double SwFlyFreeFrame::getFrameRotation() const
 
     if(nullptr != pSwNoTextFrame)
     {
-        return pSwNoTextFrame->getFrameRotation();
+        return getFrameRotation_from_SwNoTextFrame(*pSwNoTextFrame);
     }
 
     // no rotation
diff --git a/sw/source/core/layout/wsfrm.cxx b/sw/source/core/layout/wsfrm.cxx
index 5f766af16fce..972083bd273d 100644
--- a/sw/source/core/layout/wsfrm.cxx
+++ b/sw/source/core/layout/wsfrm.cxx
@@ -105,11 +105,34 @@ SwFrameAreaDefinition::FramePrintAreaWriteAccess::~FramePrintAreaWriteAccess()
     }
 }
 
-void SwFrameAreaDefinition::createFrameAreaTransformations(
-    basegfx::B2DHomMatrix& rFrameAreaTransformation,
-    basegfx::B2DHomMatrix& rFramePrintAreaTransformation,
+// RotateFlyFrame3 - Support for Transformations
+basegfx::B2DHomMatrix SwFrameAreaDefinition::getFrameAreaTransformation() const
+{
+    // default implementation hands out FrameArea (outer frame)
+    const SwRect& rFrameArea(getFrameArea());
+
+    return basegfx::utils::createScaleTranslateB2DHomMatrix(
+        rFrameArea.Width(), rFrameArea.Height(),
+        rFrameArea.Left(), rFrameArea.Top());
+}
+
+basegfx::B2DHomMatrix SwFrameAreaDefinition::getFramePrintAreaTransformation() const
+{
+    // default implementation hands out FramePrintArea (outer frame)
+    // Take into account that FramePrintArea is relative to FrameArea
+    const SwRect& rFrameArea(getFrameArea());
+    const SwRect& rFramePrintArea(getFramePrintArea());
+
+    return basegfx::utils::createScaleTranslateB2DHomMatrix(
+        rFramePrintArea.Width(), rFramePrintArea.Height(),
+        rFramePrintArea.Left() + rFrameArea.Left(),
+        rFramePrintArea.Top() + rFrameArea.Top());
+}
+
+void TransformableSwFrame::createFrameAreaTransformations(
+    const SwFrameAreaDefinition& rSwFrameAreaDefinition,
     double fRotation,
-    const basegfx::B2DPoint& rCenter) const
+    const basegfx::B2DPoint& rCenter)
 {
     // save Transformations to rFrameAreaTransformation and
     // rFramePrintAreaTransformation. Do not forget that PrintArea
@@ -119,75 +142,117 @@ void SwFrameAreaDefinition::createFrameAreaTransformations(
             rCenter.getX(),
             rCenter.getY(),
             fRotation));
-    rFrameAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
-        getFrameArea().Width(), getFrameArea().Height(),
-        getFrameArea().Left(), getFrameArea().Top());
-    rFramePrintAreaTransformation = aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
-        getFramePrintArea().Width(), getFramePrintArea().Height(),
-        getFramePrintArea().Left() + getFrameArea().Left(), getFramePrintArea().Top() + getFrameArea().Top());
+    const SwRect& rFrameArea(rSwFrameAreaDefinition.getFrameArea());
+    const SwRect& rFramePrintArea(rSwFrameAreaDefinition.getFramePrintArea());
+
+    setLocalFrameAreaTransformation(
+        aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
+            rFrameArea.Width(), rFrameArea.Height(),
+            rFrameArea.Left(), rFrameArea.Top()));
+    setLocalFramePrintAreaTransformation(
+        aRotateAroundCenter * basegfx::utils::createScaleTranslateB2DHomMatrix(
+            rFramePrintArea.Width(), rFramePrintArea.Height(),
+            rFramePrintArea.Left() + rFrameArea.Left(), rFramePrintArea.Top() + rFrameArea.Top()));
 }
 
-void SwFrameAreaDefinition::setFrameAreaDefinitionsToBoundRangesOfTransformations(
-    const basegfx::B2DHomMatrix& rFrameAreaTransformation,
-    const basegfx::B2DHomMatrix& rFramePrintAreaTransformation)
+void TransformableSwFrame::setFrameAreaDefinitionsToBoundRangesOfTransformations(
+    SwFrameAreaDefinition& rSwFrameAreaDefinition)
 {
-    if(!rFrameAreaTransformation.isIdentity())
+    if(!getLocalFrameAreaTransformation().isIdentity())
     {
         basegfx::B2DRange aRangeFrameArea(0.0, 0.0, 1.0, 1.0);
-
-        aRangeFrameArea.transform(rFrameAreaTransformation);
-
+        aRangeFrameArea.transform(getLocalFrameAreaTransformation());
         const SwRect aNewFrm(
             basegfx::fround(aRangeFrameArea.getMinX()), basegfx::fround(aRangeFrameArea.getMinY()),
             basegfx::fround(aRangeFrameArea.getWidth()), basegfx::fround(aRangeFrameArea.getHeight()));
 
-        if(aNewFrm != getFrameArea())
+        if(aNewFrm != rSwFrameAreaDefinition.getFrameArea())
         {
-            maFrameArea = aNewFrm;
+            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(rSwFrameAreaDefinition);
+            aFrm.setSwRect(aNewFrm);
         }
     }
 
-    if(!rFramePrintAreaTransformation.isIdentity())
+    if(!getLocalFramePrintAreaTransformation().isIdentity())
     {
         basegfx::B2DRange aRangeFramePrintArea(0.0, 0.0, 1.0, 1.0);
-
-        aRangeFramePrintArea.transform(rFramePrintAreaTransformation);
-
+        aRangeFramePrintArea.transform(getLocalFramePrintAreaTransformation());
         const SwRect aNewPrt(
-            basegfx::fround(aRangeFramePrintArea.getMinX()) - getFrameArea().Left(),
-            basegfx::fround(aRangeFramePrintArea.getMinY()) - getFrameArea().Top(),
+            basegfx::fround(aRangeFramePrintArea.getMinX()) - rSwFrameAreaDefinition.getFrameArea().Left(),
+            basegfx::fround(aRangeFramePrintArea.getMinY()) - rSwFrameAreaDefinition.getFrameArea().Top(),
             basegfx::fround(aRangeFramePrintArea.getWidth()),
             basegfx::fround(aRangeFramePrintArea.getHeight()));
 
-        if(aNewPrt != getFramePrintArea())
+        if(aNewPrt != rSwFrameAreaDefinition.getFramePrintArea())
         {
-            maFramePrintArea = aNewPrt;
+            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(rSwFrameAreaDefinition);
+            aPrt.setSwRect(aNewPrt);
         }
     }
 }
 
-// RotateFlyFrame3 - Support for Transformations
-basegfx::B2DHomMatrix SwFrame::getFrameAreaTransformation() const
+void TransformableSwFrame::updateTransformationsAndFrameAreaDefinitions(
+    SwFrameAreaDefinition& rSwFrameAreaDefinition,
+    double fRotation,
+    const basegfx::B2DPoint& rCenter)
 {
-    // default implementation hands out FrameArea (outer frame)
-    const SwRect& rFrameArea(getFrameArea());
+    createFrameAreaTransformations(
+        rSwFrameAreaDefinition,
+        fRotation,
+        rCenter);
 
-    return basegfx::utils::createScaleTranslateB2DHomMatrix(
-        rFrameArea.Width(), rFrameArea.Height(),
-        rFrameArea.Left(), rFrameArea.Top());
+    setFrameAreaDefinitionsToBoundRangesOfTransformations(
+        rSwFrameAreaDefinition);
 }
 
-basegfx::B2DHomMatrix SwFrame::getFramePrintAreaTransformation() const
+void TransformableSwFrame::resetAreaDefinitionsToUntransformed(
+    SwFrameAreaDefinition& rSwFrameAreaDefinition)
 {
-    // default implementation hands out FramePrintArea (outer frame)
-    // Take into account that FramePrintArea is relative to FrameArea
-    const SwRect& rFrameArea(getFrameArea());
-    const SwRect& rFramePrintArea(getFramePrintArea());
+    // calculate center of object
+    basegfx::B2DPoint aCenter(getLocalFrameAreaTransformation() * basegfx::B2DPoint(0.5, 0.5));
 
-    return basegfx::utils::createScaleTranslateB2DHomMatrix(
-        rFramePrintArea.Width(), rFramePrintArea.Height(),
-        rFramePrintArea.Left() + rFrameArea.Left(),
-        rFramePrintArea.Top() + rFrameArea.Top());
+    if(!getLocalFrameAreaTransformation().isIdentity())
+    {
+        basegfx::B2DTuple aScale, aTranslate;
+        double fRotate(0.0), fShearX(0.0);
+        getLocalFrameAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+        const SwRect aNewFrm(
+            basegfx::fround(aCenter.getX() - (0.5 * aScale.getX())),
+            basegfx::fround(aCenter.getY() - (0.5 * aScale.getY())),
+            basegfx::fround(aScale.getX()),
+            basegfx::fround(aScale.getY()));
+
+        if(aNewFrm != rSwFrameAreaDefinition.getFrameArea())
+        {
+            SwFrameAreaDefinition::FrameAreaWriteAccess aFrm(rSwFrameAreaDefinition);
+            aFrm.setSwRect(aNewFrm);
+        }
+    }
+
+    if(!getLocalFramePrintAreaTransformation().isIdentity())
+    {
+        basegfx::B2DTuple aScale, aTranslate;
+        double fRotate(0.0), fShearX(0.0);
+        getLocalFramePrintAreaTransformation().decompose(aScale, aTranslate, fRotate, fShearX);
+        const SwRect aNewPrt(
+            basegfx::fround(aCenter.getX() - (0.5 * aScale.getX())) - rSwFrameAreaDefinition.getFrameArea().Left(),
+            basegfx::fround(aCenter.getY() - (0.5 * aScale.getY())) - rSwFrameAreaDefinition.getFrameArea().Top(),
+            basegfx::fround(aScale.getX()),
+            basegfx::fround(aScale.getY()));
+
+        if(aNewPrt != rSwFrameAreaDefinition.getFramePrintArea())
+        {
+            SwFrameAreaDefinition::FramePrintAreaWriteAccess aPrt(rSwFrameAreaDefinition);
+            aPrt.setSwRect(aNewPrt);
+        }
+    }
+}
+
+void TransformableSwFrame::resetAreaDefinitionsToTransformed(
+    SwFrameAreaDefinition& rSwFrameAreaDefinition)
+{
+    setFrameAreaDefinitionsToBoundRangesOfTransformations(
+        rSwFrameAreaDefinition);
 }
 
 SwFrame::SwFrame( SwModify *pMod, SwFrame* pSib )
commit 9b136d5e69b86f81785d6ed9bfe3059a5ef97a2c
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Tue Nov 7 18:18:44 2017 +0100

    RotateFlyFrame: Late-Updating of Areas
    
    When Layouting the update of the Areas is needed,
    but during layout needs to be stable on the unrotated
    values. Hard to find the right spot to do this, decided
    to use the inner/outer frame, layout both, and trigger
    the updates when the inner frame is layouted to non-
    rotated Areas for inner and outer frame. Still not sure
    oif this will be correct, but is close to working well.
    Some repaints/updates missing
    
    Change-Id: I3d7dcbf624f3f32392e5e98420cb348d11d7d322

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 4a040cedfb9d..1accccb8e492 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -470,8 +470,15 @@ const Size& SwNoTextFrame::GetSize() const
     return pFly->getFramePrintArea().SSize();
 }
 
-void SwNoTextFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
+void SwNoTextFrame::MakeAll(vcl::RenderContext* pRenderContext)
 {
+    if(GetUpper() && !GetUpper()->isFrameAreaDefinitionValid())
+    {
+        // outer frame *needs* to be layouted first, force this by calling
+        // ::Calc directly
+        GetUpper()->Calc(pRenderContext);
+    }
+
     SwContentNotify aNotify( this );
     SwBorderAttrAccess aAccess( SwFrame::GetCache(), this );
     const SwBorderAttrs &rAttrs = *aAccess.Get();
@@ -495,9 +502,9 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
         }
     }
 
-    // RotateFlyFrame3 - outer frame
+    // RotateFlyFrame3 - inner frame
     // After the unrotated layout is finished, apply possible set rotation to it
-    const double fRotation(getRotation());
+    const double fRotation(getFrameRotation());
 
     if(basegfx::fTools::equalZero(fRotation))
     {
@@ -507,25 +514,49 @@ void SwNoTextFrame::MakeAll(vcl::RenderContext* /*pRenderContext*/)
     }
     else
     {
-        // save Transformations to local maFrameAreaTransformation
-        // and maFramePrintAreaTransformation.
-        const Point aCenter(getFrameArea().Center());
-        const basegfx::B2DPoint aB2DCenter(aCenter.X(), aCenter.Y());
-
-        createFrameAreaTransformations(
-            maFrameAreaTransformation,
-            maFramePrintAreaTransformation,
-            fRotation,
-            aB2DCenter);
-
-        // create BoundRects of FrameAreas and re-set the FrameArea definitions
-        // to represent the rotated geometry in the layout object
-        setFrameAreaDefinitionsToBoundRangesOfTransformations(
-            maFrameAreaTransformation,
-            maFramePrintAreaTransformation);
+        const bool bMeValid(isFrameAreaDefinitionValid());
+        const bool bUpperValid(!GetUpper() || GetUpper()->isFrameAreaDefinitionValid());
+
+        if(bMeValid && bUpperValid)
+        {
+            // 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());
+
+            updateTransformationsAndAreas(
+                fRotation,
+                aB2DCenter);
+
+            if(GetUpper())
+            {
+                SwFlyFreeFrame *pFly = dynamic_cast< SwFlyFreeFrame* >(GetUpper());
+
+                if(pFly)
+                {
+                    pFly->updateTransformationsAndAreas(
+                        fRotation,
+                        aB2DCenter);
+                }
+            }
+        }
     }
 }
 
+void SwNoTextFrame::updateTransformationsAndAreas(
+    double fRotation,
+    const basegfx::B2DPoint& rCenter)
+{
+    createFrameAreaTransformations(
+        maFrameAreaTransformation,
+        maFramePrintAreaTransformation,
+        fRotation,
+        rCenter);
+
+    setFrameAreaDefinitionsToBoundRangesOfTransformations(
+        maFrameAreaTransformation,
+        maFramePrintAreaTransformation);
+}
+
 // RotateFlyFrame3 - Support for Transformations - outer frame
 basegfx::B2DHomMatrix SwNoTextFrame::getFrameAreaTransformation() const
 {
@@ -551,9 +582,9 @@ basegfx::B2DHomMatrix SwNoTextFrame::getFramePrintAreaTransformation() const
     return SwContentFrame::getFramePrintAreaTransformation();
 }
 
-// RotateFlyFrame3 - outer frame
+// RotateFlyFrame3 - inner frame
 // Check if we contain a SwGrfNode and get possible rotation from it
-double SwNoTextFrame::getRotation() const
+double SwNoTextFrame::getFrameRotation() const
 {
     const SwNoTextNode* pSwNoTextNode(nullptr != GetNode() ? GetNode()->GetNoTextNode() : nullptr);
 
@@ -571,8 +602,8 @@ double SwNoTextFrame::getRotation() const
         }
     }
 
-    // call parent
-    return SwContentFrame::getRotation();
+    // no rotation
+    return 0.0;
 }
 
 /** Calculate the Bitmap's site, if needed */
@@ -735,12 +766,12 @@ void SwNoTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
                             // and LayoutFrame (outer, GetUpper). It is possible to only invalidate
                             // the outer frame, but that leads to an in-between state that gets
                             // potentially painted
-                            InvalidateAll_();
-
                             if(GetUpper())
                             {
                                 GetUpper()->InvalidateAll_();
                             }
+
+                            InvalidateAll_();

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list