[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - 8 commits - basegfx/source include/basegfx include/svx officecfg/registry sd/source svx/sdi svx/source sw/inc sw/sdi sw/source sw/uiconfig xmloff/source

Armin Le Grand Armin.Le.Grand at cib.de
Sat Oct 21 14:16:05 UTC 2017


 basegfx/source/matrix/b2dhommatrixtools.cxx                         |   43 
 include/basegfx/matrix/b2dhommatrixtools.hxx                        |    8 
 include/svx/svdobj.hxx                                              |    4 
 include/svx/svdovirt.hxx                                            |    3 
 include/svx/svxids.hrc                                              |    1 
 officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu |    8 
 sd/source/ui/view/Outliner.cxx                                      |    4 
 svx/sdi/svx.sdi                                                     |   17 
 svx/source/sidebar/possize/PosSizePropertyPanel.cxx                 |    1 
 svx/source/svdraw/svddrgmt.cxx                                      |  489 +++-------
 svx/source/svdraw/svdmrkv.cxx                                       |   79 +
 svx/source/svdraw/svdobj.cxx                                        |    6 
 svx/source/svdraw/svdovirt.cxx                                      |    6 
 sw/inc/fesh.hxx                                                     |    3 
 sw/sdi/_grfsh.sdi                                                   |   14 
 sw/sdi/grfsh.sdi                                                    |    9 
 sw/source/core/doc/notxtfrm.cxx                                     |   39 
 sw/source/core/draw/dflyobj.cxx                                     |  174 +++
 sw/source/core/draw/dview.cxx                                       |   24 
 sw/source/core/frmedt/feshview.cxx                                  |   23 
 sw/source/core/inc/dflyobj.hxx                                      |   15 
 sw/source/core/inc/frmtool.hxx                                      |    7 
 sw/source/ui/frmdlg/frmpage.cxx                                     |   31 
 sw/source/uibase/frmdlg/frmmgr.cxx                                  |   22 
 sw/source/uibase/inc/frmmgr.hxx                                     |    3 
 sw/source/uibase/inc/frmpage.hxx                                    |    6 
 sw/source/uibase/shells/frmsh.cxx                                   |   25 
 sw/source/uibase/shells/grfsh.cxx                                   |  172 ++-
 sw/uiconfig/sglobal/menubar/menubar.xml                             |    1 
 sw/uiconfig/sglobal/popupmenu/graphic.xml                           |    1 
 sw/uiconfig/sglobal/toolbar/graphicobjectbar.xml                    |    1 
 sw/uiconfig/sweb/menubar/menubar.xml                                |    1 
 sw/uiconfig/sweb/popupmenu/graphic.xml                              |    1 
 sw/uiconfig/swform/menubar/menubar.xml                              |    1 
 sw/uiconfig/swform/popupmenu/graphic.xml                            |    1 
 sw/uiconfig/swform/toolbar/graphicobjectbar.xml                     |    1 
 sw/uiconfig/swreport/menubar/menubar.xml                            |    1 
 sw/uiconfig/swreport/popupmenu/graphic.xml                          |    1 
 sw/uiconfig/swreport/toolbar/graphicobjectbar.xml                   |    1 
 sw/uiconfig/swriter/menubar/menubar.xml                             |    1 
 sw/uiconfig/swriter/popupmenu/graphic.xml                           |    1 
 sw/uiconfig/swriter/toolbar/graphicobjectbar.xml                    |    2 
 sw/uiconfig/swriter/ui/notebookbar.ui                               |   26 
 sw/uiconfig/swriter/ui/picturepage.ui                               |  147 ++-
 sw/uiconfig/swxform/menubar/menubar.xml                             |    1 
 sw/uiconfig/swxform/popupmenu/graphic.xml                           |    1 
 sw/uiconfig/swxform/toolbar/graphicobjectbar.xml                    |    1 
 xmloff/source/text/XMLTextFrameContext.cxx                          |    5 
 48 files changed, 1009 insertions(+), 423 deletions(-)

New commits:
commit be8d86cc63a0ecd434b8c3f15fceafeaddac8710
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Oct 5 22:00:35 2017 +0200

    RotGrfFlyFrame: Clang error fix
    
    Change-Id: Ifae68d4d5a17446f01c97ce2e94cd0419217259e

diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx
index 877d0dc1eac2..2bd03bfce93c 100644
--- a/sw/source/core/draw/dview.cxx
+++ b/sw/source/core/draw/dview.cxx
@@ -831,11 +831,7 @@ void SwDrawView::CheckPossibilities()
                 pFrame = pFly->GetAnchorFrame();
                 if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
                 {
-                    // SwNoTextNode& rNoTNd = const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>((static_cast<const SwContentFrame*>(pFly->Lower()))->GetNode()));
-                    // SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
-                    // SwOLENode* pOLENd = rNoTNd.GetOLENode();
-
-                    const SwContentFrame* pCntFr = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pFly->Lower()));
+                    const SwContentFrame* pCntFr(static_cast<const SwContentFrame*>(pFly->Lower()));
                     const SwOLENode* pOLENd = pCntFr->GetNode()->GetOLENode();
                     const SwGrfNode* pGrfNd = pCntFr->GetNode()->GetGrfNode();
 
commit 7606f9c38a1aedc74af6a6b17275fc878458c97b
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Wed Oct 4 17:44:24 2017 +0200

    RotGrfFlyFrame: Added interactive rotation mode
    
    The FlyFrames containing a graphic now support an
    interactive rotation mode. Added a rotation icon to the
    Toolbar close to right/left 90degree rotation. When
    activated, works as similar to draw object mode as
    possible. Shear and move of the rotation center is
    deactivated since not supported. It uses as much of the
    existing interaction stuff as possible.
    
    Change-Id: Ia1a4e5c064d8576b114c3fcf3a96ccb42c9372bb

diff --git a/basegfx/source/matrix/b2dhommatrixtools.cxx b/basegfx/source/matrix/b2dhommatrixtools.cxx
index 013bb7d23703..a2cdedf77b03 100644
--- a/basegfx/source/matrix/b2dhommatrixtools.cxx
+++ b/basegfx/source/matrix/b2dhommatrixtools.cxx
@@ -364,7 +364,8 @@ namespace basegfx
         {
             basegfx::B2DHomMatrix aRetval;
 
-            // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees
+            // RotGrfFlyFrame: Create a transformation that maps the range inside of itself
+            // so that it fits, takes as much space as possible and keeps the aspect ratio
             if(0.0 != fRotate)
             {
                 // Fit rotated graphic to center of available space, keeping page ratio:
diff --git a/include/svx/svdobj.hxx b/include/svx/svdobj.hxx
index 3b8c5b9848ae..3e75235abc9d 100644
--- a/include/svx/svdobj.hxx
+++ b/include/svx/svdobj.hxx
@@ -524,6 +524,10 @@ public:
     void SingleObjectPainter(OutputDevice& rOut) const;
     bool LineGeometryUsageIsNecessary() const;
 
+    // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation, that
+    // means no change of the rotation point (only centered) and no shear allowed
+    virtual bool HasLimitedRotation() const;
+
     // Returns a copy of the object. Every inherited class must reimplement this (in class Foo
     // it should be sufficient to do "virtual Foo* Clone() const { return CloneHelper< Foo >(); }".
     // Note that this function uses operator= internally.
diff --git a/include/svx/svdovirt.hxx b/include/svx/svdovirt.hxx
index 7ee8c6f2fa47..9933f8fce281 100644
--- a/include/svx/svdovirt.hxx
+++ b/include/svx/svdovirt.hxx
@@ -69,6 +69,9 @@ public:
     virtual OUString TakeObjNameSingul() const override;
     virtual OUString TakeObjNamePlural() const override;
 
+    // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation
+    virtual bool HasLimitedRotation() const override;
+
     virtual basegfx::B2DPolyPolygon TakeXorPoly() const override;
     virtual sal_uInt32 GetHdlCount() const override;
     virtual SdrHdl* GetHdl(sal_uInt32 nHdlNum) const override;
diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index 5e9206ae84fa..3a284b89c079 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -2124,18 +2124,28 @@ bool SdrDragRotate::BeginSdrDrag()
 {
     SdrHdl* pH=GetHdlList().GetHdl(HDL_REF1);
 
-    if (pH!=nullptr)
+    if (nullptr != pH)
     {
         Show();
         DragStat().Ref1()=pH->GetPos();
         nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
         return true;
     }
-    else
+
+    // RotGrfFlyFrame: Support rotation around center *without* Ref1 (normally
+    // the rotation point)
+    const Rectangle aLocalMarkRect(getSdrDragView().GetMarkedObjRect());
+
+    if(!aLocalMarkRect.IsEmpty())
     {
-        OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found.");
-        return false;
+        Show();
+        DragStat().Ref1() = aLocalMarkRect.Center();
+        nAngle0=GetAngle(DragStat().GetStart()-DragStat().GetRef1());
+        return true;
     }
+
+    OSL_FAIL("SdrDragRotate::BeginSdrDrag(): No reference point handle found.");
+    return false;
 }
 
 basegfx::B2DHomMatrix SdrDragRotate::getCurrentTransformation()
diff --git a/svx/source/svdraw/svdmrkv.cxx b/svx/source/svdraw/svdmrkv.cxx
index ac14c709521f..90576118d16e 100644
--- a/svx/source/svdraw/svdmrkv.cxx
+++ b/svx/source/svdraw/svdmrkv.cxx
@@ -625,14 +625,22 @@ void SdrMarkView::SetMarkHandles()
         const size_t nMarkCount=GetMarkedObjectCount();
         bool bStdDrag=meDragMode==SDRDRAG_MOVE;
         bool bSingleTextObjMark=false;
+        bool bLimitedRotation(false);
 
         if (nMarkCount==1)
         {
             mpMarkedObj=GetMarkedObjectByIndex(0);
-            bSingleTextObjMark =
-                mpMarkedObj &&
-                dynamic_cast<const SdrTextObj*>( mpMarkedObj) !=  nullptr &&
-                static_cast<SdrTextObj*>(mpMarkedObj)->IsTextFrame();
+
+            if(nullptr != mpMarkedObj)
+            {
+                bSingleTextObjMark =
+                    mpMarkedObj &&
+                    dynamic_cast<const SdrTextObj*>( mpMarkedObj) !=  nullptr &&
+                    static_cast<SdrTextObj*>(mpMarkedObj)->IsTextFrame();
+
+                // RotGrfFlyFrame: we may have limited rotation
+                bLimitedRotation = SDRDRAG_ROTATE == meDragMode && mpMarkedObj->HasLimitedRotation();
+            }
         }
 
         bool bFrmHdl=ImpIsFrameHandles();
@@ -752,27 +760,59 @@ void SdrMarkView::SetMarkHandles()
                 }
                 else
                 {
-                    bool bWdt0=aRect.Left()==aRect.Right();
-                    bool bHgt0=aRect.Top()==aRect.Bottom();
+                    const bool bWdt0(aRect.Left() == aRect.Right());
+                    const bool bHgt0(aRect.Top() == aRect.Bottom());
+
                     if (bWdt0 && bHgt0)
                     {
-                        maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(),HDL_UPLFT));
+                        maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), HDL_UPLFT));
                     }
                     else if (!bStdDrag && (bWdt0 || bHgt0))
                     {
-                        maHdlList.AddHdl(new SdrHdl(aRect.TopLeft()    ,HDL_UPLFT));
-                        maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(),HDL_LWRGT));
+                        maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), HDL_UPLFT));
+                        maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(), HDL_LWRGT));
                     }
                     else
                     {
-                        if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopLeft()     ,HDL_UPLFT));
-                        if (          !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopCenter()   ,HDL_UPPER));
-                        if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopRight()    ,HDL_UPRGT));
-                        if (!bWdt0          ) maHdlList.AddHdl(new SdrHdl(aRect.LeftCenter()  ,HDL_LEFT ));
-                        if (!bWdt0          ) maHdlList.AddHdl(new SdrHdl(aRect.RightCenter() ,HDL_RIGHT));
-                        if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomLeft()  ,HDL_LWLFT));
-                        if (          !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomCenter(),HDL_LOWER));
-                        if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomRight() ,HDL_LWRGT));
+                        if (!bWdt0 && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), HDL_UPLFT));
+                        }
+
+                        if (!bLimitedRotation && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.TopCenter(), HDL_UPPER));
+                        }
+
+                        if (!bWdt0 && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.TopRight(), HDL_UPRGT));
+                        }
+
+                        if (!bLimitedRotation && !bWdt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.LeftCenter(), HDL_LEFT));
+                        }
+
+                        if (!bLimitedRotation && !bWdt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.RightCenter(), HDL_RIGHT));
+                        }
+
+                        if (!bWdt0 && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.BottomLeft(), HDL_LWLFT));
+                        }
+
+                        if (!bLimitedRotation && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.BottomCenter(), HDL_LOWER));
+                        }
+
+                        if (!bWdt0 && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(), HDL_LWRGT));
+                        }
                     }
                 }
             }
@@ -870,7 +910,10 @@ void SdrMarkView::SetMarkHandles()
         }
 
         // rotation point/axis of reflection
-        AddDragModeHdl(meDragMode);
+        if(!bLimitedRotation)
+        {
+            AddDragModeHdl(meDragMode);
+        }
 
         // sort handles
         maHdlList.Sort();
diff --git a/svx/source/svdraw/svdobj.cxx b/svx/source/svdraw/svdobj.cxx
index 0316c9a416ea..daaf8f0c37e6 100644
--- a/svx/source/svdraw/svdobj.cxx
+++ b/svx/source/svdraw/svdobj.cxx
@@ -938,6 +938,12 @@ bool SdrObject::LineGeometryUsageIsNecessary() const
     return (eXLS != drawing::LineStyle_NONE);
 }
 
+bool SdrObject::HasLimitedRotation() const
+{
+    // RotGrfFlyFrame: Default is false, support full rotation
+    return false;
+}
+
 SdrObject* SdrObject::Clone() const
 {
     return CloneHelper< SdrObject >();
diff --git a/svx/source/svdraw/svdovirt.cxx b/svx/source/svdraw/svdovirt.cxx
index 587363daf1dc..c1dba64df038 100644
--- a/svx/source/svdraw/svdovirt.cxx
+++ b/svx/source/svdraw/svdovirt.cxx
@@ -171,6 +171,12 @@ OUString SdrVirtObj::TakeObjNamePlural() const
     return sName.makeStringAndClear();
 }
 
+bool SdrVirtObj::HasLimitedRotation() const
+{
+    // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation
+    return rRefObj.HasLimitedRotation();
+}
+
 basegfx::B2DPolyPolygon SdrVirtObj::TakeXorPoly() const
 {
     basegfx::B2DPolyPolygon aPolyPolygon(rRefObj.TakeXorPoly());
diff --git a/sw/inc/fesh.hxx b/sw/inc/fesh.hxx
index a99b4e453edd..28678cff7014 100644
--- a/sw/inc/fesh.hxx
+++ b/sw/inc/fesh.hxx
@@ -508,6 +508,9 @@ public:
     // Start cropping the selected image
     void StartCropImage();
 
+    // RotGrfFlyFrame: check if RotationMode is possibe
+    bool IsRotationOfSwGrfNodePossible() const;
+
     size_t IsObjSelected() const;   ///< @return object count, but doesn't count the objects in groups.
     bool IsObjSelected( const SdrObject& rObj ) const;
     bool IsObjSameLevelWithMarked(const SdrObject* pObj) const;
diff --git a/sw/sdi/grfsh.sdi b/sw/sdi/grfsh.sdi
index 956a0c82b443..78ecc504e98a 100644
--- a/sw/sdi/grfsh.sdi
+++ b/sw/sdi/grfsh.sdi
@@ -24,5 +24,14 @@ shell SwGrfShell : SwBaseShell
 
 {
     import TextGraphic;
+
+    // RotGrfFlyFrame: need SID_OBJECT_ROTATE for FlyFrames with graphic
+    SID_OBJECT_ROTATE
+    [
+        Export = FALSE;
+        ExecMethod = Execute ;
+        StateMethod = GetAttrState ;
+        DisableFlags="SW_DISABLE_ON_PROTECTED_CURSOR";
+    ]
 }
 
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index 18b62d8c9b11..a1f2a6c3adb7 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -49,6 +49,7 @@
 #include "rootfrm.hxx"
 #include "wrtsh.hxx"
 #include <ndgrf.hxx>
+#include <frmmgr.hxx>
 
 #include <svx/sdr/properties/defaultproperties.hxx>
 #include <basegfx/range/b2drange.hxx>
@@ -368,6 +369,64 @@ basegfx::B2DRange SwVirtFlyDrawObj::getInnerBound() const
     return aInnerRange;
 }
 
+bool SwVirtFlyDrawObj::ContainsSwGrfNode() const
+{
+    // RotGrfFlyFrame: Check if this is a SwGrfNode
+    const SwFlyFrame* pFlyFrame(GetFlyFrame());
+
+    if(nullptr != pFlyFrame && pFlyFrame->Lower() && pFlyFrame->Lower()->IsNoTextFrame())
+    {
+        const SwContentFrame* pCntFr(static_cast<const SwContentFrame*>(pFlyFrame->Lower()));
+
+        if(nullptr != pCntFr)
+        {
+            const SwGrfNode* pGrfNd(pCntFr->GetNode()->GetGrfNode());
+
+            return nullptr != pGrfNd;
+        }
+    }
+
+    return false;
+}
+
+bool SwVirtFlyDrawObj::HasLimitedRotation() const
+{
+    // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation.
+    // This is the case for SwGrfNode instances
+    return ContainsSwGrfNode();
+}
+
+void SwVirtFlyDrawObj::Rotate(const Point& rRef, long nAngle, double sn, double cs)
+{
+    if(ContainsSwGrfNode())
+    {
+        // RotGrfFlyFrame: Here is where the positively completed rotate interaction is executed.
+        // Rotation is in 1/100th degree and may be signed (!)
+        nAngle /= 10;
+
+        while(nAngle < 0)
+        {
+            nAngle += 3600;
+        }
+
+        if(0 != nAngle)
+        {
+            // RotGrfFlyFrame: Add transformation to placeholder object
+            Size aSize;
+            const sal_uInt16 nOldRot(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize));
+            SwWrtShell *pSh = dynamic_cast<SwWrtShell*>( GetFlyFrame()->getRootFrame()->GetCurrShell() );
+            SwFlyFrameAttrMgr aMgr(false, pSh, Frmmgr_Type::NONE);
+
+            aMgr.SetRotation(nOldRot, (nOldRot + static_cast<sal_uInt16>(nAngle)) % 3600, aSize);
+        }
+    }
+    else
+    {
+        // call parent
+        SdrVirtObj::Rotate(rRef, nAngle, sn, cs);
+    }
+}
+
 sdr::contact::ViewContact* SwVirtFlyDrawObj::CreateObjectSpecificViewContact()
 {
     // need an own ViewContact (VC) to allow creation of a specialized primitive
@@ -491,7 +550,9 @@ void SwVirtFlyDrawObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
     rInfo.bSelectAllowed     = rInfo.bMoveAllowed =
     rInfo.bResizeFreeAllowed = rInfo.bResizePropAllowed = true;
 
-    rInfo.bRotateFreeAllowed = rInfo.bRotate90Allowed =
+    // RotGrfFlyFrame: Some rotation may be allowed
+    rInfo.bRotateFreeAllowed = rInfo.bRotate90Allowed = HasLimitedRotation();
+
     rInfo.bMirrorFreeAllowed = rInfo.bMirror45Allowed =
     rInfo.bMirror90Allowed   = rInfo.bShearAllowed    =
     rInfo.bCanConvToPath     = rInfo.bCanConvToPoly   =
@@ -938,7 +999,7 @@ void SwVirtFlyDrawObj::Crop(const Point& rRef, const Fraction& xFact, const Frac
 }
 
 // RotGrfFlyFrame: Helper to access possible rotation of Graphic contained in FlyFrame
-sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame() const
+sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(Size& rSize) const
 {
     sal_uInt16 nRetval(0);
     const SwNoTextFrame* pNoTx = dynamic_cast< const SwNoTextFrame* >(GetFlyFrame()->Lower());
@@ -953,6 +1014,7 @@ sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame() const
             const SwAttrSet& rSet = pGrfNd->GetSwAttrSet();
             const SwRotationGrf& rRotation = rSet.GetRotationGrf();
 
+            rSize = rRotation.GetUnrotatedSize();
             nRetval = rRotation.GetValue();
         }
     }
@@ -965,25 +1027,19 @@ SdrObject* SwVirtFlyDrawObj::getFullDragClone() const
     // call parent
     SdrObject* pRetval = SdrVirtObj::getFullDragClone();
 
-    if(pRetval)
+    if(pRetval && ContainsSwGrfNode())
     {
         // RotGrfFlyFrame: Add transformation to placeholder object
-        const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame());
-
-        if(0 != nRotation)
-        {
-            const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0));
-            const Rectangle aTmpOutRect(GetFlyFrame()->Frame().SVRect());
-            const basegfx::B2DRange aTargetRange(
-                aTmpOutRect.Left(), aTmpOutRect.Top(),
-                aTmpOutRect.Right(), aTmpOutRect.Bottom());
-            const basegfx::B2DHomMatrix aTargetTransform(
-                basegfx::tools::createRotateAroundCenterKeepAspectRatioStayInsideRange(
-                    aTargetRange,
-                    fRotate));
+        Size aSize;
+        const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize));
+        const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0));
+        const basegfx::B2DRange aTargetRange(getInnerBound());
+        const basegfx::B2DHomMatrix aTargetTransform(
+            basegfx::tools::createRotateAroundCenterKeepAspectRatioStayInsideRange(
+                aTargetRange,
+                fRotate));
 
-            pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon());
-        }
+        pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon());
     }
 
     return pRetval;
@@ -1001,7 +1057,8 @@ void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const
 
         if(!aTargetRange.isEmpty())
         {
-            const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame());
+            Size aSize;
+            const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame(aSize));
             const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0));
             const basegfx::B2DHomMatrix aTargetTransform(
                 basegfx::tools::createRotateAroundCenterKeepAspectRatioStayInsideRange(
@@ -1078,12 +1135,4 @@ SdrObject* SwVirtFlyDrawObj::CheckMacroHit( const SdrObjMacroHitRec& rRec ) cons
     return SdrObject::CheckMacroHit( rRec );
 }
 
-// Dragging
-
-bool SwVirtFlyDrawObj::supportsFullDrag() const
-{
-    // call parent
-    return SdrVirtObj::supportsFullDrag();
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx
index 495485c82bdd..877d0dc1eac2 100644
--- a/sw/source/core/draw/dview.cxx
+++ b/sw/source/core/draw/dview.cxx
@@ -44,6 +44,7 @@
 #include "doc.hxx"
 #include "mdiexp.hxx"
 #include <ndole.hxx>
+#include <ndgrf.hxx>
 #include <fmtanchr.hxx>
 #include "shellres.hxx"
 #include <IDocumentUndoRedo.hxx>
@@ -816,6 +817,8 @@ void SwDrawView::CheckPossibilities()
     const SdrMarkList &rMrkList = GetMarkedObjectList();
     bool bProtect = false;
     bool bSzProtect = false;
+    bool bRotate(false);
+
     for ( size_t i = 0; !bProtect && i < rMrkList.GetMarkCount(); ++i )
     {
         const SdrObject *pObj = rMrkList.GetMark( i )->GetMarkedSdrObj();
@@ -828,10 +831,18 @@ void SwDrawView::CheckPossibilities()
                 pFrame = pFly->GetAnchorFrame();
                 if ( pFly->Lower() && pFly->Lower()->IsNoTextFrame() )
                 {
-                    SwOLENode *pNd = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pFly->Lower()))->GetNode()->GetOLENode();
-                    if ( pNd )
+                    // SwNoTextNode& rNoTNd = const_cast<SwNoTextNode&>(*static_cast<const SwNoTextNode*>((static_cast<const SwContentFrame*>(pFly->Lower()))->GetNode()));
+                    // SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
+                    // SwOLENode* pOLENd = rNoTNd.GetOLENode();
+
+                    const SwContentFrame* pCntFr = const_cast<SwContentFrame*>(static_cast<const SwContentFrame*>(pFly->Lower()));
+                    const SwOLENode* pOLENd = pCntFr->GetNode()->GetOLENode();
+                    const SwGrfNode* pGrfNd = pCntFr->GetNode()->GetGrfNode();
+
+                    if ( pOLENd )
                     {
-                        uno::Reference < embed::XEmbeddedObject > xObj = pNd->GetOLEObj().GetOleRef();
+                        const uno::Reference < embed::XEmbeddedObject > xObj = const_cast< SwOLEObj& >(pOLENd->GetOLEObj()).GetOleRef();
+
                         if ( xObj.is() )
                         {
                             // --> improvement for the future, when more
@@ -849,6 +860,13 @@ void SwDrawView::CheckPossibilities()
                                 bMoveProtect = true;
                         }
                     }
+                    else if(pGrfNd)
+                    {
+                        // RotGrfFlyFrame: GraphicNode allows rotation(s). The loop ew are in stops
+                        // as soon as bMoveProtect is set, but since rotation is valid only with
+                        // a single object selected this makes no difference
+                        bRotate = true;
+                    }
                 }
             }
         }
@@ -876,6 +894,10 @@ void SwDrawView::CheckPossibilities()
     }
     bMoveProtect    |= bProtect;
     bResizeProtect  |= bProtect || bSzProtect;
+
+    // RotGrfFlyFrame: allow rotation when SwGrfNode is selected and not size protected
+    bRotateFreeAllowed |= bRotate && !bProtect;
+    bRotate90Allowed |= bRotateFreeAllowed;
 }
 
 /// replace marked <SwDrawVirtObj>-objects by its reference object for delete marked objects.
diff --git a/sw/source/core/frmedt/feshview.cxx b/sw/source/core/frmedt/feshview.cxx
index 6c8f7c158155..e41ee3965cde 100644
--- a/sw/source/core/frmedt/feshview.cxx
+++ b/sw/source/core/frmedt/feshview.cxx
@@ -991,6 +991,29 @@ bool SwFEShell::IsObjSelected( const SdrObject& rObj ) const
                     ->IsObjMarked( const_cast< SdrObject * >( &rObj ) );
 }
 
+bool SwFEShell::IsRotationOfSwGrfNodePossible() const
+{
+    // RotGrfFlyFrame: check if RotationMode is possibe
+    const SdrView *pSdrView = Imp()->GetDrawView();
+
+    if(pSdrView)
+    {
+        const SdrMarkList& rList(pSdrView->GetMarkedObjectList());
+
+        if(1 == rList.GetMarkCount())
+        {
+            const SwVirtFlyDrawObj* pVirtFlyDraw(dynamic_cast< const SwVirtFlyDrawObj* >(rList.GetMark(0)->GetMarkedSdrObj()));
+
+            if(nullptr != pVirtFlyDraw)
+            {
+                return pVirtFlyDraw->ContainsSwGrfNode();
+            }
+        }
+    }
+
+    return false;
+}
+
 bool SwFEShell::IsObjSameLevelWithMarked(const SdrObject* pObj) const
 {
     if (pObj)
diff --git a/sw/source/core/inc/dflyobj.hxx b/sw/source/core/inc/dflyobj.hxx
index 0218aa5f020b..77befafe37bf 100644
--- a/sw/source/core/inc/dflyobj.hxx
+++ b/sw/source/core/inc/dflyobj.hxx
@@ -64,7 +64,7 @@ private:
 
     // RotGrfFlyFrame: Helper to acces sthe rotation angle (in 10th degrees, left-handed)
     // of a GraphicFrame
-    sal_uInt16 getPossibleRotationFromFraphicFrame() const;
+    sal_uInt16 getPossibleRotationFromFraphicFrame(Size& rSize) const;
 
 protected:
     // AW: Need own sdr::contact::ViewContact since AnchorPos from parent is
@@ -81,6 +81,8 @@ public:
     basegfx::B2DRange getOuterBound() const;
     basegfx::B2DRange getInnerBound() const;
 
+    // RotGrfFlyFrame: Check if this is a SwGrfNode
+    bool ContainsSwGrfNode() const;
 
     SwVirtFlyDrawObj(SdrObject& rNew, SwFlyFrame* pFly);
     virtual ~SwVirtFlyDrawObj();
@@ -109,6 +111,7 @@ public:
                                     const Fraction& yFact, bool bUnsetRelative = true) override;
     virtual       void       Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override;
     virtual       void       addCropHandles(SdrHdlList& rTarget) const override;
+    virtual       void       Rotate(const Point& rRef, long nAngle, double sn, double cs) override;
 
     // FullDrag support
     virtual SdrObject* getFullDragClone() const override;
@@ -127,8 +130,8 @@ public:
     virtual SdrObject* CheckMacroHit       (const SdrObjMacroHitRec& rRec) const override;
     virtual Pointer    GetMacroPointer     (const SdrObjMacroHitRec& rRec) const override;
 
-    // FullDrag support
-    virtual bool supportsFullDrag() const override;
+    // RotGrfFlyFrame: If true, this SdrObject supports only limited rotation.
+    virtual bool HasLimitedRotation() const override;
 };
 
 #endif
diff --git a/sw/source/uibase/frmdlg/frmmgr.cxx b/sw/source/uibase/frmdlg/frmmgr.cxx
index 287206837ee0..e7e4a4439c15 100644
--- a/sw/source/uibase/frmdlg/frmmgr.cxx
+++ b/sw/source/uibase/frmdlg/frmmgr.cxx
@@ -578,9 +578,9 @@ void SwFlyFrameAttrMgr::SetHeightSizeType( SwFrameSize eType )
 void SwFlyFrameAttrMgr::SetRotation(sal_uInt16 nOld, sal_uInt16 nNew, const Size& rUnrotatedSize)
 {
     // RotGrfFlyFrame: Central handling of real change of rotation here, all adaptions use this.
-    // Adaption of pos/size may be wanted in the future. Already tried to keep last SIze in
+    // Adaption of pos/size may be wanted in the future. Already tried to keep last Size in
     // UnrotatedSize in the SwRotationGrf Item, but this will lead to various problems. Also tried
-    // to use m_aSet.Put(...) as in other methods (also read methods for Rotation/UnrotatedSize) but
+    // to use m_aSet.Put(...) as in other methods (also tried read methods for Rotation/UnrotatedSize) but
     // somehow the needed ID (RES_GRFATR_ROTATION) is *not* in the SfxItemSet of the Frame, so for
     // now set directly. Undo/Redo is preserved by AttributeChange
     if(nOld != nNew)
diff --git a/sw/source/uibase/shells/grfsh.cxx b/sw/source/uibase/shells/grfsh.cxx
index d5906887cb66..a0be6cf02a9b 100644
--- a/sw/source/uibase/shells/grfsh.cxx
+++ b/sw/source/uibase/shells/grfsh.cxx
@@ -124,6 +124,27 @@ void SwGrfShell::Execute(SfxRequest &rReq)
     sal_uInt16 nSlot = rReq.GetSlot();
     switch(nSlot)
     {
+        case SID_OBJECT_ROTATE:
+        {
+            // RotGrfFlyFrame: start rotation when possible
+            SdrView* pSdrView = rSh.GetDrawViewWithValidMarkList();
+
+            if(rSh.IsRotationOfSwGrfNodePossible() && pSdrView->IsRotateAllowed())
+            {
+                if(GetView().IsDrawRotate())
+                {
+                    rSh.SetDragMode(SDRDRAG_MOVE);
+                }
+                else
+                {
+                    rSh.SetDragMode(SDRDRAG_ROTATE);
+                }
+
+                GetView().FlipDrawRotate();
+            }
+        }
+        break;
+
         case SID_TWAIN_TRANSFER:
         {
             GetView().ExecuteScan( rReq );
@@ -692,6 +713,23 @@ void SwGrfShell::GetAttrState(SfxItemSet &rSet)
         bool bDisable = bParentCntProt;
         switch( nWhich )
         {
+        case SID_OBJECT_ROTATE:
+        {
+            // RotGrfFlyFrame: steer rotation state
+            const bool bIsRotate(GetView().IsDrawRotate());
+            SdrView* pSdrView = rSh.GetDrawViewWithValidMarkList();
+
+            if(!bIsRotate && !pSdrView->IsRotateAllowed())
+            {
+                rSet.DisableItem(nWhich);
+            }
+            else
+            {
+                rSet.Put(SfxBoolItem(nWhich, bIsRotate));
+            }
+
+            break;
+        }
         case SID_INSERT_GRAPHIC:
         case FN_FORMAT_GRAFIC_DLG:
         case SID_TWAIN_TRANSFER:
diff --git a/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml b/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml
index acb93ba6feb2..c9348c34f0b4 100644
--- a/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml
+++ b/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml
@@ -28,6 +28,7 @@
  <toolbar:toolbaritem xlink:href=".uno:FlipHorizontal" toolbar:helpid="20425"/>
  <toolbar:toolbaritem xlink:href=".uno:RotateLeft" toolbar:helpid=""/>
  <toolbar:toolbaritem xlink:href=".uno:RotateRight" toolbar:helpid=""/>
+ <toolbar:toolbaritem xlink:href=".uno:ToggleObjectRotateMode"/>
  <toolbar:toolbaritem xlink:href=".uno:RotateReset" toolbar:visible="false"/>
  <toolbar:toolbarseparator/>
  <toolbar:toolbaritem xlink:href=".uno:GrafTransparence" toolbar:helpid="10869"/>
commit 8de0ddbf8cf6d9d402fbc7d746ffd519bacc239e
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Fri Sep 29 12:35:44 2017 +0200

    RotGrfFlyFrame: Corrected position for CropHandles
    
    Position was taken from OuterBound FlyFrame, even in current
    master which is wrong. There can be a distance defined between
    InnerBound and OuterBound that has to be taken into account
    
    Change-Id: Id88f99c0b218bd26fa1daa5e8215eced00c0baa6

diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index 12f9dd7f9de5..18b62d8c9b11 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -48,6 +48,7 @@
 #include "pagefrm.hxx"
 #include "rootfrm.hxx"
 #include "wrtsh.hxx"
+#include <ndgrf.hxx>
 
 #include <svx/sdr/properties/defaultproperties.hxx>
 #include <basegfx/range/b2drange.hxx>
@@ -972,10 +973,10 @@ SdrObject* SwVirtFlyDrawObj::getFullDragClone() const
         if(0 != nRotation)
         {
             const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0));
-            const Rectangle aOutRect(GetFlyFrame()->Frame().SVRect());
+            const Rectangle aTmpOutRect(GetFlyFrame()->Frame().SVRect());
             const basegfx::B2DRange aTargetRange(
-                aOutRect.Left(), aOutRect.Top(),
-                aOutRect.Right(), aOutRect.Bottom());
+                aTmpOutRect.Left(), aTmpOutRect.Top(),
+                aTmpOutRect.Right(), aTmpOutRect.Bottom());
             const basegfx::B2DHomMatrix aTargetTransform(
                 basegfx::tools::createRotateAroundCenterKeepAspectRatioStayInsideRange(
                     aTargetRange,
@@ -993,10 +994,10 @@ void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const
     // RotGrfFlyFrame: Adapt to possible rotated Graphic contained in FlyFrame
     if(GetFlyFrame()->Frame().HasArea())
     {
-        const Rectangle aOutRect(GetFlyFrame()->Frame().SVRect());
-        const basegfx::B2DRange aTargetRange(
-            aOutRect.Left(), aOutRect.Top(),
-            aOutRect.Right(), aOutRect.Bottom());
+        // Use InnerBound, OuterBound (same as GetFlyFrame()->Frame().SVRect())
+        // may have a distance to InnerBound which needs to be taken into acocunt.
+        // The Graphic is mapped to InnerBound, as is the rotated Graphic.
+        const basegfx::B2DRange aTargetRange(getInnerBound());
 
         if(!aTargetRange.isEmpty())
         {
diff --git a/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml b/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml
index c8e53464d60e..acb93ba6feb2 100644
--- a/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml
+++ b/sw/uiconfig/swriter/toolbar/graphicobjectbar.xml
@@ -28,7 +28,7 @@
  <toolbar:toolbaritem xlink:href=".uno:FlipHorizontal" toolbar:helpid="20425"/>
  <toolbar:toolbaritem xlink:href=".uno:RotateLeft" toolbar:helpid=""/>
  <toolbar:toolbaritem xlink:href=".uno:RotateRight" toolbar:helpid=""/>
- <toolbar:toolbaritem xlink:href=".uno:RotateReset"/>
+ <toolbar:toolbaritem xlink:href=".uno:RotateReset" toolbar:visible="false"/>
  <toolbar:toolbarseparator/>
  <toolbar:toolbaritem xlink:href=".uno:GrafTransparence" toolbar:helpid="10869"/>
  <toolbar:toolbarseparator/>
diff --git a/sw/uiconfig/swxform/toolbar/graphicobjectbar.xml b/sw/uiconfig/swxform/toolbar/graphicobjectbar.xml
index 4b95da3b4fcc..3b7d58354b0e 100644
--- a/sw/uiconfig/swxform/toolbar/graphicobjectbar.xml
+++ b/sw/uiconfig/swxform/toolbar/graphicobjectbar.xml
@@ -30,7 +30,7 @@
  <toolbar:toolbaritem xlink:href=".uno:FlipHorizontal" toolbar:helpid="20425"/>
  <toolbar:toolbaritem xlink:href=".uno:RotateLeft" toolbar:helpid=""/>
  <toolbar:toolbaritem xlink:href=".uno:RotateRight" toolbar:helpid=""/>
- <toolbar:toolbaritem xlink:href=".uno:RotateReset"/>
+ <toolbar:toolbaritem xlink:href=".uno:RotateReset" toolbar:visible="false"/>
  <toolbar:toolbaritem xlink:href=".uno:Crop" toolbar:helpid=""/>
  <toolbar:toolbarseparator/>
  <toolbar:toolbaritem xlink:href=".uno:FrameDialog" toolbar:helpid="20458"/>
commit a3ba4e6287a2593c0a2479f0b90aba043adcd3a7
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Fri Sep 29 10:42:43 2017 +0200

    RotGrfFlyFrame: Implemented Handle Update on rotation change
    
    WIth rotaiton being allowed the handle visualisation may be
    dependent on this, so it is necessary to refresh their
    visualisation on rotation chnage, e.g. for crop handles
    
    Change-Id: I218e326894999381fc4058b7eba432491a0cf23b

diff --git a/include/basegfx/matrix/b2dhommatrixtools.hxx b/include/basegfx/matrix/b2dhommatrixtools.hxx
index f6bcf2691436..5eea03f864db 100644
--- a/include/basegfx/matrix/b2dhommatrixtools.hxx
+++ b/include/basegfx/matrix/b2dhommatrixtools.hxx
@@ -230,6 +230,7 @@ namespace basegfx
             const B2DVector& getScale() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maScale; }
             const B2DVector& getTranslate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return maTranslate; }
             double getRotate() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfRotate; }
+            double getShearX() const { const_cast< B2DHomMatrixBufferedOnDemandDecompose* >(this)->impCheckDecompose(); return mfShearX; }
         };
     } // end of namespace tools
 
diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index 986dafd14ec3..5e9206ae84fa 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -597,14 +597,14 @@ void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
     {
         // do something special since the object size is in the polygon
         // break up matrix to get the scale
-        const basegfx::tools::B2DHomMatrixBufferedDecompose aDecomp(aObjectTransform);
+        const basegfx::tools::B2DHomMatrixBufferedDecompose aTmpDecomp(aObjectTransform);
 
         // get polygon's position and size
         const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange());
 
         // get the scaling factors (do not mirror, this is in the object transformation)
-        const double fScaleX(fabs(aDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
-        const double fScaleY(fabs(aDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));
+        const double fScaleX(fabs(aTmpDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
+        const double fScaleY(fabs(aTmpDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));
 
         // prepare transform matrix for polygon
         basegfx::B2DHomMatrix aPolyTransform(
@@ -3685,16 +3685,16 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
     pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon);
 
     {   // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
-        const basegfx::tools::B2DHomMatrixBufferedDecompose aDecomp(aOriginalMatrix);
+        const basegfx::tools::B2DHomMatrixBufferedDecompose aTmpDecomp(aOriginalMatrix);
 
-        if(!basegfx::fTools::equalZero(aDecomp.getShearX()))
+        if(!basegfx::fTools::equalZero(aTmpDecomp.getShearX()))
         {
             bShearCorrected = true;
             aOriginalMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
-                aDecomp.getScale(),
-                -aDecomp.getShearX(),
-                aDecomp.getRotate(),
-                aDecomp.getTranslate());
+                aTmpDecomp.getScale(),
+                -aTmpDecomp.getShearX(),
+                aTmpDecomp.getRotate(),
+                aTmpDecomp.getTranslate());
         }
     }
 
@@ -3768,13 +3768,13 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
     // aDiscreteChangeMatrix, go to concrete sizes now.
     // Create the unrotated original rectangle and the unrotated modified
     // rectangle as Ranges
-    const basegfx::tools::B2DHomMatrixBufferedDecompose aDecomp(aOriginalMatrix);
+    const basegfx::tools::B2DHomMatrixBufferedDecompose aOriginalMatrixDecomp(aOriginalMatrix);
 
     // prepare unsheared/unrotated versions of the old and new transformation
     const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate(
         basegfx::tools::createScaleTranslateB2DHomMatrix(
-            basegfx::absolute(aDecomp.getScale()),
-            aDecomp.getTranslate()));
+            basegfx::absolute(aOriginalMatrixDecomp.getScale()),
+            aOriginalMatrixDecomp.getTranslate()));
 
     // create the ranges for these
     basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
@@ -3812,13 +3812,13 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
         if(bShearCorrected)
         {
             // back-correct shear
-            const basegfx::tools::B2DHomMatrixBufferedDecompose aDecomp(aNewObjectMatrix);
+            const basegfx::tools::B2DHomMatrixBufferedDecompose aTmpDecomp(aNewObjectMatrix);
 
             aNewObjectMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
-                aDecomp.getScale(),
-                -aDecomp.getShearX(),
-                aDecomp.getRotate(),
-                aDecomp.getTranslate());
+                aTmpDecomp.getScale(),
+                -aTmpDecomp.getShearX(),
+                aTmpDecomp.getRotate(),
+                aTmpDecomp.getTranslate());
         }
 
         // apply change to object by applying the unit coordinate change followed
diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 26068117e155..3fbb20ac629e 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -632,6 +632,27 @@ void SwNoTextFrame::Modify( const SfxPoolItem* pOld, const SfxPoolItem* pNew )
                                 GetItemState( n, false ))
                 {
                     CLEARCACHE
+
+                    if(RES_GRFATR_ROTATION == n)
+                    {
+                        // RotGrfFlyFrame: Update Handles in view, these may be rotation-dependent
+                        // (e.g. crop handles) and need a visualisation update
+                        if ( GetNode()->GetNodeType() == ND_GRFNODE )
+                        {
+                            SwGrfNode* pNd = static_cast<SwGrfNode*>( GetNode());
+                            SwViewShell *pVSh = pNd->GetDoc()->getIDocumentLayoutAccess().GetCurrentViewShell();
+
+                            if(pVSh)
+                            {
+                                SdrView* pDrawView = pVSh->GetDrawView();
+
+                                if(pDrawView)
+                                {
+                                    pDrawView->AdjustMarkHdl();
+                                }
+                            }
+                        }
+                    }
                     break;
                 }
             if( RES_GRFATR_END == n )           // not found
commit 0258313527f0622c1330563a496fdfb9dd7795bc
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Sep 28 13:08:35 2017 +0200

    RotGrfFlyFrame: Encapsulated matrix decomposes
    
    Change-Id: I432766970ef06c7d85a0056d3f24280cf2acd47d

diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index 78a601ef3bb4..986dafd14ec3 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -597,21 +597,20 @@ void SdrDragMethod::applyCurrentTransformationToSdrObject(SdrObject& rTarget)
     {
         // do something special since the object size is in the polygon
         // break up matrix to get the scale
-        basegfx::B2DTuple aScale;
-        basegfx::B2DTuple aTranslate;
-        double fRotate, fShearX;
-        aObjectTransform.decompose(aScale, aTranslate, fRotate, fShearX);
+        const basegfx::tools::B2DHomMatrixBufferedDecompose aDecomp(aObjectTransform);
 
         // get polygon's position and size
         const basegfx::B2DRange aPolyRange(aObjectPolyPolygon.getB2DRange());
 
         // get the scaling factors (do not mirror, this is in the object transformation)
-        const double fScaleX(fabs(aScale.getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
-        const double fScaleY(fabs(aScale.getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));
+        const double fScaleX(fabs(aDecomp.getScale().getX()) / (basegfx::fTools::equalZero(aPolyRange.getWidth()) ? 1.0 : aPolyRange.getWidth()));
+        const double fScaleY(fabs(aDecomp.getScale().getY()) / (basegfx::fTools::equalZero(aPolyRange.getHeight()) ? 1.0 : aPolyRange.getHeight()));
 
         // prepare transform matrix for polygon
-        basegfx::B2DHomMatrix aPolyTransform(basegfx::tools::createTranslateB2DHomMatrix(
-            -aPolyRange.getMinX(), -aPolyRange.getMinY()));
+        basegfx::B2DHomMatrix aPolyTransform(
+            basegfx::tools::createTranslateB2DHomMatrix(
+                -aPolyRange.getMinX(),
+                -aPolyRange.getMinY()));
         aPolyTransform.scale(fScaleX, fScaleY);
 
         // transform the polygon
@@ -3686,18 +3685,16 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
     pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon);
 
     {   // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
-        basegfx::B2DTuple aScale, aTranslate;
-        double fRotate(0.0), fShearX(0.0);
-        aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+        const basegfx::tools::B2DHomMatrixBufferedDecompose aDecomp(aOriginalMatrix);
 
-        if(!basegfx::fTools::equalZero(fShearX))
+        if(!basegfx::fTools::equalZero(aDecomp.getShearX()))
         {
             bShearCorrected = true;
             aOriginalMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
-                aScale,
-                -fShearX,
-                fRotate,
-                aTranslate);
+                aDecomp.getScale(),
+                -aDecomp.getShearX(),
+                aDecomp.getRotate(),
+                aDecomp.getTranslate());
         }
     }
 
@@ -3771,17 +3768,13 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
     // aDiscreteChangeMatrix, go to concrete sizes now.
     // Create the unrotated original rectangle and the unrotated modified
     // rectangle as Ranges
-    basegfx::B2DTuple aScale, aTranslate;
-    double fRotate, fShearX;
-
-    // get access to scale and translate
-    aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+    const basegfx::tools::B2DHomMatrixBufferedDecompose aDecomp(aOriginalMatrix);
 
     // prepare unsheared/unrotated versions of the old and new transformation
     const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate(
         basegfx::tools::createScaleTranslateB2DHomMatrix(
-            basegfx::absolute(aScale),
-            aTranslate));
+            basegfx::absolute(aDecomp.getScale()),
+            aDecomp.getTranslate()));
 
     // create the ranges for these
     basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
@@ -3819,16 +3812,13 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
         if(bShearCorrected)
         {
             // back-correct shear
-            basegfx::B2DTuple aScale;
-            basegfx::B2DTuple aTranslate;
-            double fRotate(0.0), fShearX(0.0);
+            const basegfx::tools::B2DHomMatrixBufferedDecompose aDecomp(aNewObjectMatrix);
 
-            aNewObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
             aNewObjectMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
-                aScale,
-                -fShearX,
-                fRotate,
-                aTranslate);
+                aDecomp.getScale(),
+                -aDecomp.getShearX(),
+                aDecomp.getRotate(),
+                aDecomp.getTranslate());
         }
 
         // apply change to object by applying the unit coordinate change followed
commit 0015fddcaf08b59910cb795d84d5c89aa63b0430
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Sep 28 10:20:15 2017 +0200

    RotGrfFlyFrame: Adapt Crop functionality to rotated Graphic
    
    The FlyFrame which may contain a Graphic needs working Crop,
    interactive and in core. Adapted this to work with now possible
    rotation, changed common code in svx which has to handle cases
    for Draw/Impress/Calc and Writer differently. Tried to use as
    much in common as possible. Additionally furter adaptions
    to rotation itself.
    
    Change-Id: Ia961e9490e2627c74220b186116f5aa4fcabca78

diff --git a/basegfx/source/matrix/b2dhommatrixtools.cxx b/basegfx/source/matrix/b2dhommatrixtools.cxx
index 89ab91424706..013bb7d23703 100644
--- a/basegfx/source/matrix/b2dhommatrixtools.cxx
+++ b/basegfx/source/matrix/b2dhommatrixtools.cxx
@@ -358,6 +358,48 @@ namespace basegfx
             return aRetval;
         }
 
+        BASEGFX_DLLPUBLIC B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange(
+            const basegfx::B2DRange& rTargetRange,
+            double fRotate)
+        {
+            basegfx::B2DHomMatrix aRetval;
+
+            // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees
+            if(0.0 != fRotate)
+            {
+                // Fit rotated graphic to center of available space, keeping page ratio:
+                // Adapt scaling ratio of unit object and rotate it
+                aRetval.scale(1.0, rTargetRange.getHeight() / rTargetRange.getWidth());
+                aRetval.rotate(fRotate);
+
+                // get the range to see where we are in unit coordinates
+                basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0);
+                aFullRange.transform(aRetval);
+
+                // detect needed scales in X/Y and choose the smallest for staying inside the
+                // available space while keeping aspect ratio of the source
+                const double fScaleX(rTargetRange.getWidth() / aFullRange.getWidth());
+                const double fScaleY(rTargetRange.getHeight() / aFullRange.getHeight());
+                const double fScaleMin(std::min(fScaleX, fScaleY));
+
+                // TopLeft to zero, then scale, then move to center of available space
+                aRetval.translate(-aFullRange.getMinX(), -aFullRange.getMinY());
+                aRetval.scale(fScaleMin, fScaleMin);
+                aRetval.translate(
+                    rTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()),
+                    rTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight()));
+            }
+            else
+            {
+                // just scale/translate needed
+                aRetval *= createScaleTranslateB2DHomMatrix(
+                    rTargetRange.getRange(),
+                    rTargetRange.getMinimum());
+            }
+
+            return aRetval;
+        }
+
         /// special for the case to map from source range to target range
         B2DHomMatrix createSourceRangeTargetRangeTransform(
             const B2DRange& rSourceRange,
diff --git a/include/basegfx/matrix/b2dhommatrixtools.hxx b/include/basegfx/matrix/b2dhommatrixtools.hxx
index 1c4c13b38985..f6bcf2691436 100644
--- a/include/basegfx/matrix/b2dhommatrixtools.hxx
+++ b/include/basegfx/matrix/b2dhommatrixtools.hxx
@@ -126,6 +126,13 @@ namespace basegfx
                 fRadiant);
         }
 
+        /// special for creating a mapping for a Range rotated around it's center
+        /// while keeping AspectRatio unchanged and staying inside the given Range
+        /// by optimally using the available space (no overlap or outside allowed)
+        BASEGFX_DLLPUBLIC B2DHomMatrix createRotateAroundCenterKeepAspectRatioStayInsideRange(
+            const basegfx::B2DRange& rTargetRange,
+            double fRotate);
+
         /// special for the case to map from source range to target range
         BASEGFX_DLLPUBLIC B2DHomMatrix createSourceRangeTargetRangeTransform(
             const B2DRange& rSourceRange,
diff --git a/sd/source/ui/view/Outliner.cxx b/sd/source/ui/view/Outliner.cxx
index 3a4ba9e87d48..caaa5d7b0cdc 100644
--- a/sd/source/ui/view/Outliner.cxx
+++ b/sd/source/ui/view/Outliner.cxx
@@ -795,11 +795,11 @@ bool Outliner::SearchAndReplaceOnce(std::vector<SearchSelection>* pSelections)
         // convert to twips if in 100thmm (seems as if LibreOfficeKit is based on twips?). Do this
         // here where we have the only place needing this, *not* in ImpEditView::GetSelectionRectangles
         // which makes that method unusable for others
-        if (pOutlinerView->GetWindow() && MapUnit::MAP_100TH_MM == pOutlinerView->GetWindow()->GetMapMode().GetMapUnit())
+        if (pOutlinerView->GetWindow() && MAP_100TH_MM == pOutlinerView->GetWindow()->GetMapMode().GetMapUnit())
         {
             for (Rectangle& rRectangle : aLogicRects)
             {
-                rRectangle = OutputDevice::LogicToLogic(rRectangle, MapUnit::MAP_100TH_MM, MapUnit::MAP_TWIP);
+                rRectangle = OutputDevice::LogicToLogic(rRectangle, MAP_100TH_MM, MAP_TWIP);
             }
         }
 
diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index fc96f3d74f5c..78a601ef3bb4 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -3613,200 +3613,62 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
 {
     Hide();
 
-    if( DragStat().GetDX()==0 && DragStat().GetDY()==0 )
+    if(0 == DragStat().GetDX() && 0 == DragStat().GetDY())
+    {
+        // no change, done
         return false;
+    }
 
     const SdrMarkList& rMarkList = getSdrDragView().GetMarkedObjectList();
 
-    if( rMarkList.GetMarkCount() != 1 )
+    if(1 != rMarkList.GetMarkCount())
+    {
+        // Crop only with single Object selected
         return false;
+    }
 
-    SdrObject* pSdrObject = rMarkList.GetMark( 0 )->GetMarkedSdrObj();
-
-    // tdf 34555: in order to implement visual crop in Writer, we need to handle two
-    // cases:
-    // EndSdrDrag when called in Impress/Draw/...: pSdrObject is a SdrGrafObj
-    // EndSdrDrag when called in Writer: pSdrObject is a SwVirtFlyDrawObj
-    // Main principle: if marked object is not SdrGrafObj, we start a generic handling
-    // based on virtual methods added to SdrObject, on MM100/Twip coordinates and so on.
-    // If marked object is SdrGrafObj, we do all the work here with matrix based
-    // coordinates.
-    if (dynamic_cast<const SdrGrafObj*>( pSdrObject) ==  nullptr) {
-        const bool bUndo = getSdrDragView().IsUndoEnabled();
-        if( bUndo )
-        {
-            OUString aUndoStr;
-            ImpTakeDescriptionStr(STR_DragMethCrop, aUndoStr);
-            getSdrDragView().BegUndo( aUndoStr );
-            getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoGeoObject(*pSdrObject));
-            // also need attr undo, the SdrGrafCropItem will be changed
-            getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pSdrObject));
-        }
-
-        // We need to produce a reference point and two (X & Y) scales
-        SdrHdl* pRef1=GetHdlList().GetHdl(HDL_UPLFT);
-        SdrHdl* pRef2=GetHdlList().GetHdl(HDL_LWRGT);
-
-        if (pRef1==nullptr || pRef2==nullptr)
-            return false;
-
-        Rectangle rect(pRef1->GetPos(),pRef2->GetPos());
-
-        Point aEnd(DragStat().GetNow());
-        Point aStart(DragStat().GetStart());
-        Point aRef(rect.Center());
-
-        // Reference point is the point opposed to the dragged handle
-        switch(GetDragHdlKind())
-        {
-            case HDL_UPLFT: aRef = rect.BottomRight();                                  break;
-            case HDL_UPPER: aRef = rect.BottomCenter(); DragStat().SetHorFixed(true);   break;
-            case HDL_UPRGT: aRef = rect.BottomLeft();                                   break;
-            case HDL_LEFT : aRef = rect.RightCenter();  DragStat().SetVerFixed(true);   break;
-            case HDL_RIGHT: aRef = rect.LeftCenter();   DragStat().SetVerFixed(true);   break;
-            case HDL_LWLFT: aRef = rect.TopRight();                                     break;
-            case HDL_LOWER: aRef = rect.TopCenter();    DragStat().SetHorFixed(true);   break;
-            case HDL_LWRGT: aRef = rect.TopLeft();                                      break;
-            default: break;
-        }
-
-        // By default, scale is new size / old size
-        long nXDiv = aStart.X()-aRef.X(); if (nXDiv==0) nXDiv=1;
-        long nYDiv = aStart.Y()-aRef.Y(); if (nYDiv==0) nYDiv=1;
-        long nXMul = aEnd.X()-aRef.X();
-        long nYMul = aEnd.Y()-aRef.Y();
-
-        if (nXDiv<0)
-        {
-            nXDiv=-nXDiv;
-            nXMul=-nXMul;
-        }
-
-        if (nYDiv<0)
-        {
-            nYDiv=-nYDiv;
-            nYMul=-nYMul;
-        }
-
-        // Take ortho into account.
-        bool bXNeg=nXMul<0; if (bXNeg) nXMul=-nXMul;
-        bool bYNeg=nYMul<0; if (bYNeg) nYMul=-nYMul;
-        bool bOrtho=getSdrDragView().IsOrtho() || !getSdrDragView().IsResizeAllowed();
-
-        if (!DragStat().IsHorFixed() && !DragStat().IsVerFixed())
-        {
-            if (std::abs(nXDiv)<=1 || std::abs(nYDiv)<=1)
-                bOrtho=false;
-
-            if (bOrtho)
-            {
-                if ((Fraction(nXMul,nXDiv)>Fraction(nYMul,nYDiv)) !=getSdrDragView().IsBigOrtho())
-                {
-                    nXMul=nYMul;
-                    nXDiv=nYDiv;
-                }
-                else
-                {
-                    nYMul=nXMul;
-                    nYDiv=nXDiv;
-                }
-            }
-        }
-        else
-        {
-            if (bOrtho)
-            {
-                if (DragStat().IsHorFixed())
-                {
-                    bXNeg=false;
-                    nXMul=nYMul;
-                    nXDiv=nYDiv;
-                }
-
-                if (DragStat().IsVerFixed())
-                {
-                    bYNeg=false;
-                    nYMul=nXMul;
-                    nYDiv=nXDiv;
-                }
-            }
-            else
-            {
-                if (DragStat().IsHorFixed())
-                {
-                    bXNeg=false;
-                    nXMul=1;
-                    nXDiv=1;
-                }
+    // prepare for SdrGrafObj or others. This code has to work with usual
+    // SdrGrafObj's from Draw/Impress/Calc, but also with SdrObjects from
+    // Writer. It would be better to handle this in Writer directly, but
+    // there are currently no easy mechanisms to plug an alternative interaction
+    // from there
+    SdrObject* pSdrObject = rMarkList.GetMark(0)->GetMarkedSdrObj();
+    struct SdrObjDeleter { void operator()(SdrObject* b) { SdrObject::Free(b); }};
+    std::unique_ptr< SdrObject, SdrObjDeleter > pFullDragClone;
+    bool bExternal(false);
+    SdrObject* pExternalSdrObject(nullptr);
 
-                if (DragStat().IsVerFixed())
-                {
-                    bYNeg=false;
-                    nYMul=1;
-                    nYDiv=1;
-                }
-            }
-        }
-        Fraction aXFact(nXMul,nXDiv);
-        Fraction aYFact(nYMul,nYDiv);
-        Fraction aMaxFact(0x7FFFFFFF,1);
+    // RotGrfFlyFrame: Crop decision for DrawingLayer/Writer now
+    // locally, no two-in-one methods any more
+    if (nullptr != pSdrObject && dynamic_cast< const SdrGrafObj* >(pSdrObject) ==  nullptr)
+    {
+        // If Writer, get the already offered for interaction SdrGrafObj
+        // and set up for using that replacement object that contains the
+        // real transformation. That SdrObject is owned and has to be deleted,
+        // so use a std::unique_ptr with special handling for the protected
+        // SDrObject destructor
+        pFullDragClone.reset(pSdrObject->getFullDragClone());
 
-        if (bOrtho)
+        if(pFullDragClone && dynamic_cast< SdrGrafObj* >(pFullDragClone.get()))
         {
-            if (aXFact>aMaxFact)
-            {
-                aXFact=aMaxFact;
-                aYFact=aMaxFact;
-            }
-
-            if (aYFact>aMaxFact)
-            {
-                aXFact=aMaxFact;
-                aYFact=aMaxFact;
-            }
+            bExternal = true;
+            pExternalSdrObject = pSdrObject;
+            pSdrObject = pFullDragClone.get();
         }
-
-        if (bXNeg)
-            aXFact=Fraction(-aXFact.GetNumerator(),aXFact.GetDenominator());
-
-        if (bYNeg)
-            aYFact=Fraction(-aYFact.GetNumerator(),aYFact.GetDenominator());
-
-        // With Ref point (opposed to dragged point), X scale and Y scale,
-        // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj
-        // crop
-        pSdrObject->Crop(aRef, aXFact, aYFact);
-
-        if( bUndo )
-            getSdrDragView().EndUndo();
-
-        // Job's done
-        return true;
     }
 
-    // This part of code handles the case where pSdrObject is SdrGrafObj
-
+    // get and check for SdrGrafObj now
     SdrGrafObj* pObj = dynamic_cast<SdrGrafObj*>( pSdrObject );
-    if( !pObj || (pObj->GetGraphicType() == GRAPHIC_NONE) || (pObj->GetGraphicType() == GRAPHIC_DEFAULT) )
-        return false;
 
-    const GraphicObject& rGraphicObject = pObj->GetGraphicObject();
-    const MapMode aMapMode100thmm(MAP_100TH_MM);
-    Size aGraphicSize(rGraphicObject.GetPrefSize());
-
-    if( MAP_PIXEL == rGraphicObject.GetPrefMapMode().GetMapUnit() )
-        aGraphicSize = Application::GetDefaultDevice()->PixelToLogic( aGraphicSize, aMapMode100thmm );
-    else
-        aGraphicSize = OutputDevice::LogicToLogic( aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm);
-
-    if( aGraphicSize.A() == 0 || aGraphicSize.B() == 0 )
+    if(!pObj)
+    {
         return false;
+    }
 
-    const SdrGrafCropItem& rOldCrop = static_cast<const SdrGrafCropItem&>(pObj->GetMergedItem(SDRATTR_GRAFCROP));
-
-    const bool bUndo = getSdrDragView().IsUndoEnabled();
+    // no undo for external needed, done there
+    const bool bUndo(!bExternal && getSdrDragView().IsUndoEnabled());
 
-    if( bUndo )
+    if(bUndo)
     {
         OUString aUndoStr;
         ImpTakeDescriptionStr(STR_DragMethCrop, aUndoStr);
@@ -3817,20 +3679,15 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
         getSdrDragView().AddUndo( getSdrDragView().GetModel()->GetSdrUndoFactory().CreateUndoAttrObject(*pObj));
     }
 
-    // new part to commute the user's drag activities
     // get the original objects transformation
     basegfx::B2DHomMatrix aOriginalMatrix;
     basegfx::B2DPolyPolygon aPolyPolygon;
     bool bShearCorrected(false);
-
-    // get transformation from object
     pObj->TRGetBaseGeometry(aOriginalMatrix, aPolyPolygon);
 
-    {   // TTTT correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
-        basegfx::B2DTuple aScale;
-        basegfx::B2DTuple aTranslate;
+    {   // correct shear, it comes currently mirrored from TRGetBaseGeometry, can be removed with aw080
+        basegfx::B2DTuple aScale, aTranslate;
         double fRotate(0.0), fShearX(0.0);
-
         aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
 
         if(!basegfx::fTools::equalZero(fShearX))
@@ -3844,11 +3701,6 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
         }
     }
 
-    // invert it to be able to work on unit coordinates
-    basegfx::B2DHomMatrix aInverse(aOriginalMatrix);
-
-    aInverse.invert();
-
     // generate start point of original drag vector in unit coordinates (the
     // vis-a-vis of the drag point)
     basegfx::B2DPoint aLocalStart(0.0, 0.0);
@@ -3867,7 +3719,10 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
         default: break;
     }
 
-    // create the current drag position in unit coordinates
+    // create the current drag position in unit coordinates. To get there,
+    // transform back the DragPoint to UnitCoordinates
+    basegfx::B2DHomMatrix aInverse(aOriginalMatrix);
+    aInverse.invert();
     basegfx::B2DPoint aLocalCurrent(aInverse * basegfx::B2DPoint(DragStat().GetNow().X(), DragStat().GetNow().Y()));
 
     // if one of the edge handles is used, limit to X or Y drag only
@@ -3912,48 +3767,18 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
         }
     }
 
-    // preparematrix to apply to object; evtl. back-correct shear
-    basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix);
-
-    if(bShearCorrected)
-    {
-        // TTTT back-correct shear
-        basegfx::B2DTuple aScale;
-        basegfx::B2DTuple aTranslate;
-        double fRotate(0.0), fShearX(0.0);
-
-        aNewObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
-        aNewObjectMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
-            aScale,
-            -fShearX,
-            fRotate,
-            aTranslate);
-    }
-
-    // apply change to object by applying the unit coordinate change followed
-    // by the original change
-    pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon);
-
-    // the following old code uses aOldRect/aNewRect to calculate the crop change for
-    // the crop item. It implies unrotated objects, so create the unrotated original
-    // rectangle and the unrotated modified rectangle. Latter can in case of shear and/or
-    // rotation not be fetched by using
-
-    //Rectangle aNewRect( pObj->GetLogicRect() );
-
-    // as it was done before because the top-left of that new rect *will* have an offset
-    // caused by the evtl. existing shear and/or rotation, so calculate a unrotated
-    // rectangle how it would be as a result when applying the unit coordinate change
-    // to the unrotated original transformation.
-    basegfx::B2DTuple aScale;
-    basegfx::B2DTuple aTranslate;
+    // We now have the whole executed Crop in UnitCoordinates in
+    // aDiscreteChangeMatrix, go to concrete sizes now.
+    // Create the unrotated original rectangle and the unrotated modified
+    // rectangle as Ranges
+    basegfx::B2DTuple aScale, aTranslate;
     double fRotate, fShearX;
 
     // get access to scale and translate
     aOriginalMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
 
     // prepare unsheared/unrotated versions of the old and new transformation
-    const basegfx::B2DHomMatrix aMatrixOriginalNoShearNoRotate(
+    const basegfx::B2DHomMatrix aOriginalMatrixNoShearNoRotate(
         basegfx::tools::createScaleTranslateB2DHomMatrix(
             basegfx::absolute(aScale),
             aTranslate));
@@ -3961,55 +3786,129 @@ bool SdrDragCrop::EndSdrDrag(bool /*bCopy*/)
     // create the ranges for these
     basegfx::B2DRange aRangeOriginalNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
     basegfx::B2DRange aRangeNewNoShearNoRotate(0.0, 0.0, 1.0, 1.0);
+    aRangeOriginalNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate);
+    aRangeNewNoShearNoRotate.transform(aOriginalMatrixNoShearNoRotate * aDiscreteChangeMatrix);
+
+    if(bExternal)
+    {
+        // With Ref point (opposed to dragged point), X scale and Y scale,
+        // we call crop (virtual method) on pSdrObject which calls VirtFlyDrawObj
+        // crop. aRef needs to be adapted to concrete Object's boundaries which
+        // is different from Crop-Ranges. This is because the Graphic and it's
+        // SdrObject representaion is inside the FlyFrame, but not identical
+        // with it.
+        const Rectangle& rOutRect(pExternalSdrObject->GetCurrentBoundRect());
+        const basegfx::B2DHomMatrix aExternalTransform(
+            basegfx::tools::createScaleTranslateB2DHomMatrix(
+                rOutRect.getWidth(), rOutRect.getHeight(),
+                rOutRect.Left(), rOutRect.Top()));
+        const basegfx::B2DPoint aRef(aExternalTransform * aLocalStart);
+        const double fScaleX(aRangeNewNoShearNoRotate.getWidth() / aRangeOriginalNoShearNoRotate.getWidth());
+        const double fScaleY(aRangeNewNoShearNoRotate.getHeight() / aRangeOriginalNoShearNoRotate.getHeight());
+
+        pExternalSdrObject->Crop(
+            Point(basegfx::fround(aRef.getX()), basegfx::fround(aRef.getY())),
+            Fraction(fScaleX),
+            Fraction(fScaleY));
+    }
+    else
+    {
+        // prepare matrix to apply to object; evtl. back-correct shear
+        basegfx::B2DHomMatrix aNewObjectMatrix(aOriginalMatrix * aDiscreteChangeMatrix);
+
+        if(bShearCorrected)
+        {
+            // back-correct shear
+            basegfx::B2DTuple aScale;
+            basegfx::B2DTuple aTranslate;
+            double fRotate(0.0), fShearX(0.0);
 
-    aRangeOriginalNoShearNoRotate.transform(aMatrixOriginalNoShearNoRotate);
-    aRangeNewNoShearNoRotate.transform(aMatrixOriginalNoShearNoRotate * aDiscreteChangeMatrix);
-
-    // extract the old Rectangle structures
-    Rectangle aOldRect(
-        basegfx::fround(aRangeOriginalNoShearNoRotate.getMinX()),
-        basegfx::fround(aRangeOriginalNoShearNoRotate.getMinY()),
-        basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxX()),
-        basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxY()));
-    Rectangle aNewRect(
-        basegfx::fround(aRangeNewNoShearNoRotate.getMinX()),
-        basegfx::fround(aRangeNewNoShearNoRotate.getMinY()),
-        basegfx::fround(aRangeNewNoShearNoRotate.getMaxX()),
-        basegfx::fround(aRangeNewNoShearNoRotate.getMaxY()));
-
-    // continue with the old original stuff
-    if (!aOldRect.GetWidth() || !aOldRect.GetHeight())
-        throw o3tl::divide_by_zero();
-
-    double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / (double)aOldRect.GetWidth();
-    double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / (double)aOldRect.GetHeight();
-
-    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();
-
-    if(pObj->IsMirrored())
-    {
-        // mirrored X or Y, for old stuff, exchange X
-        // TTTT: check for aw080
-        sal_Int32 nTmp(nDiffLeft);
-        nDiffLeft = -nDiffRight;
-        nDiffRight = -nTmp;
-    }
-
-    sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX );
-    sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY );
-    sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX );
-    sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY );
-
-    SfxItemPool& rPool = getSdrDragView().GetModel()->GetItemPool();
-    SfxItemSet aSet( rPool, SDRATTR_GRAFCROP, SDRATTR_GRAFCROP );
-    aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) );
-    getSdrDragView().SetAttributes( aSet, false );
-
-    if( bUndo )
+            aNewObjectMatrix.decompose(aScale, aTranslate, fRotate, fShearX);
+            aNewObjectMatrix = basegfx::tools::createScaleShearXRotateTranslateB2DHomMatrix(
+                aScale,
+                -fShearX,
+                fRotate,
+                aTranslate);
+        }
+
+        // apply change to object by applying the unit coordinate change followed
+        // by the original change
+        pObj->TRSetBaseGeometry(aNewObjectMatrix, aPolyPolygon);
+
+        // extract the old Rectangle structures
+        Rectangle aOldRect(
+            basegfx::fround(aRangeOriginalNoShearNoRotate.getMinX()),
+            basegfx::fround(aRangeOriginalNoShearNoRotate.getMinY()),
+            basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxX()),
+            basegfx::fround(aRangeOriginalNoShearNoRotate.getMaxY()));
+        Rectangle aNewRect(
+            basegfx::fround(aRangeNewNoShearNoRotate.getMinX()),
+            basegfx::fround(aRangeNewNoShearNoRotate.getMinY()),
+            basegfx::fround(aRangeNewNoShearNoRotate.getMaxX()),
+            basegfx::fround(aRangeNewNoShearNoRotate.getMaxY()));
+
+        // continue with the old original stuff
+        if (!aOldRect.GetWidth() || !aOldRect.GetHeight())
+        {
+            throw o3tl::divide_by_zero();
+        }
+
+        if((pObj->GetGraphicType() == GRAPHIC_NONE) || (pObj->GetGraphicType() == GRAPHIC_DEFAULT))
+        {
+            return false;
+        }
+
+        const GraphicObject& rGraphicObject = pObj->GetGraphicObject();
+        const MapMode aMapMode100thmm(MAP_100TH_MM);
+        Size aGraphicSize(rGraphicObject.GetPrefSize());
+
+        if(MAP_PIXEL == rGraphicObject.GetPrefMapMode().GetMapUnit())
+        {
+            aGraphicSize = Application::GetDefaultDevice()->PixelToLogic(aGraphicSize, aMapMode100thmm);
+        }
+        else
+        {
+            aGraphicSize = OutputDevice::LogicToLogic(aGraphicSize, rGraphicObject.GetPrefMapMode(), aMapMode100thmm);
+        }
+
+        if(0 == aGraphicSize.Width() || 0 == aGraphicSize.Height())
+        {
+            return false;
+        }
+
+        const SdrGrafCropItem& rOldCrop = static_cast<const SdrGrafCropItem&>(pObj->GetMergedItem(SDRATTR_GRAFCROP));
+        double fScaleX = ( aGraphicSize.Width() - rOldCrop.GetLeft() - rOldCrop.GetRight() ) / (double)aOldRect.GetWidth();
+        double fScaleY = ( aGraphicSize.Height() - rOldCrop.GetTop() - rOldCrop.GetBottom() ) / (double)aOldRect.GetHeight();
+
+        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();
+
+        if(pObj->IsMirrored())
+        {
+            // mirrored X or Y, for old stuff, exchange X
+            // check for aw080
+            sal_Int32 nTmp(nDiffLeft);
+            nDiffLeft = -nDiffRight;
+            nDiffRight = -nTmp;
+        }
+
+        sal_Int32 nLeftCrop = static_cast<sal_Int32>( rOldCrop.GetLeft() + nDiffLeft * fScaleX );
+        sal_Int32 nTopCrop = static_cast<sal_Int32>( rOldCrop.GetTop() + nDiffTop * fScaleY );
+        sal_Int32 nRightCrop = static_cast<sal_Int32>( rOldCrop.GetRight() - nDiffRight * fScaleX );
+        sal_Int32 nBottomCrop = static_cast<sal_Int32>( rOldCrop.GetBottom() - nDiffBottom * fScaleY );
+
+        SfxItemPool& rPool = getSdrDragView().GetModel()->GetItemPool();
+        SfxItemSet aSet( rPool, SDRATTR_GRAFCROP, SDRATTR_GRAFCROP, 0, 0 );
+        aSet.Put( SdrGrafCropItem( nLeftCrop, nTopCrop, nRightCrop, nBottomCrop ) );
+        getSdrDragView().SetAttributes( aSet, false );
+    }
+
+    if(bUndo)
+    {
         getSdrDragView().EndUndo();
+    }
 
     return true;
 }
diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 0bcbe33cdb96..26068117e155 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -763,53 +763,24 @@ bool paintUsingPrimitivesHelper(
     return false;
 }
 
-void paintGraphicUsingPrimitivesHelper(vcl::RenderContext & rOutputDevice,
-         GraphicObject const& rGrfObj, GraphicAttr const& rGraphicAttr,
-         SwRect const& rAlignedGrfArea)
+void paintGraphicUsingPrimitivesHelper(
+    vcl::RenderContext & rOutputDevice,
+    GraphicObject const& rGrfObj,
+    GraphicAttr const& rGraphicAttr,
+    SwRect const& rAlignedGrfArea)
 {
-    // unify using GraphicPrimitive2D
+    // RotGrfFlyFrame: unify using GraphicPrimitive2D
     // -> the primitive handles all crop and mirror stuff
     // -> the primitive renderer will create the needed pdf export data
     // -> if bitmap content, it will be cached system-dependent
     const basegfx::B2DRange aTargetRange(
         rAlignedGrfArea.Left(), rAlignedGrfArea.Top(),
         rAlignedGrfArea.Right(), rAlignedGrfArea.Bottom());
-    basegfx::B2DHomMatrix aTargetTransform;
-
-    // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees
-    if(0 != rGraphicAttr.GetRotation())
-    {
-        // Fit rotated graphic to center of available space, keeping page ratio:
-        // Adapt scaling ratio of unit object and rotate it
-        const double fRotate(static_cast< double >(-rGraphicAttr.GetRotation()) * (M_PI/1800.0));
-        aTargetTransform.scale(1.0, aTargetRange.getHeight() / aTargetRange.getWidth());
-        aTargetTransform.rotate(fRotate);
-
-        // get the range to see where we are in unit coordinates
-        basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0);
-        aFullRange.transform(aTargetTransform);
-
-        // detect needed scales in X/Y and choose the smallest for staying inside the
-        // available space while keeping aspect ratio of the source
-        const double fScaleX(aTargetRange.getWidth() / aFullRange.getWidth());
-        const double fScaleY(aTargetRange.getHeight() / aFullRange.getHeight());
-        const double fScaleMin(std::min(fScaleX, fScaleY));
-
-        // TopLeft to zero, then scale, then move to center of available space
-        aTargetTransform.translate(-aFullRange.getMinX(), -aFullRange.getMinY());
-        aTargetTransform.scale(fScaleMin, fScaleMin);
-        aTargetTransform.translate(
-            aTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()),
-            aTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight()));
-    }
-    else
-    {
-        // just scale/translate needed
-        aTargetTransform *= basegfx::tools::createScaleTranslateB2DHomMatrix(
-            aTargetRange.getRange(),
-            aTargetRange.getMinimum());
-    }
-
+    const double fRotate(static_cast< double >(-rGraphicAttr.GetRotation()) * (M_PI/1800.0));
+    const basegfx::B2DHomMatrix aTargetTransform(
+        basegfx::tools::createRotateAroundCenterKeepAspectRatioStayInsideRange(
+            aTargetRange,
+            fRotate));
     drawinglayer::primitive2d::Primitive2DContainer aContent(1);
     bool bDone(false);
 
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index 8451721f02f7..12f9dd7f9de5 100644
--- a/sw/source/core/draw/dflyobj.cxx
+++ b/sw/source/core/draw/dflyobj.cxx
@@ -59,6 +59,8 @@
 #include <drawinglayer/primitive2d/baseprimitive2d.hxx>
 #include <sw_primitivetypes2d.hxx>
 #include <drawinglayer/primitive2d/sdrdecompositiontools2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <notxtfrm.hxx>
 
 using namespace ::com::sun::star;
 
@@ -934,20 +936,96 @@ void SwVirtFlyDrawObj::Crop(const Point& rRef, const Fraction& xFact, const Frac
     GetFormat()->GetDoc()->GetIDocumentUndoRedo().DoDrawUndo(false);
 }
 
-void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const
+// RotGrfFlyFrame: Helper to access possible rotation of Graphic contained in FlyFrame
+sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame() const
+{
+    sal_uInt16 nRetval(0);
+    const SwNoTextFrame* pNoTx = dynamic_cast< const SwNoTextFrame* >(GetFlyFrame()->Lower());
+
+    if(pNoTx)
+    {
+        SwNoTextNode& rNoTNd = const_cast< SwNoTextNode& >(*static_cast<const SwNoTextNode*>(pNoTx->GetNode()));
+        SwGrfNode* pGrfNd = rNoTNd.GetGrfNode();
+
+        if(nullptr != pGrfNd)
+        {
+            const SwAttrSet& rSet = pGrfNd->GetSwAttrSet();
+            const SwRotationGrf& rRotation = rSet.GetRotationGrf();
+
+            nRetval = rRotation.GetValue();
+        }
+    }
+
+    return nRetval;
+}
+
+SdrObject* SwVirtFlyDrawObj::getFullDragClone() const
 {
-    Rectangle aRect(GetSnapRect());
+    // call parent
+    SdrObject* pRetval = SdrVirtObj::getFullDragClone();
+
+    if(pRetval)
+    {
+        // RotGrfFlyFrame: Add transformation to placeholder object
+        const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame());
 
-    if(!aRect.IsEmpty())
+        if(0 != nRotation)
+        {
+            const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0));
+            const Rectangle aOutRect(GetFlyFrame()->Frame().SVRect());
+            const basegfx::B2DRange aTargetRange(
+                aOutRect.Left(), aOutRect.Top(),
+                aOutRect.Right(), aOutRect.Bottom());
+            const basegfx::B2DHomMatrix aTargetTransform(
+                basegfx::tools::createRotateAroundCenterKeepAspectRatioStayInsideRange(
+                    aTargetRange,
+                    fRotate));
+
+            pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon());
+        }
+    }
+
+    return pRetval;
+}
+
+void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const
+{
+    // RotGrfFlyFrame: Adapt to possible rotated Graphic contained in FlyFrame
+    if(GetFlyFrame()->Frame().HasArea())
     {
-       rTarget.AddHdl(new SdrCropHdl(aRect.TopLeft()     , HDL_UPLFT, 0, 0));
-       rTarget.AddHdl(new SdrCropHdl(aRect.TopCenter()   , HDL_UPPER, 0, 0));
-       rTarget.AddHdl(new SdrCropHdl(aRect.TopRight()    , HDL_UPRGT, 0, 0));
-       rTarget.AddHdl(new SdrCropHdl(aRect.LeftCenter()  , HDL_LEFT , 0, 0));
-       rTarget.AddHdl(new SdrCropHdl(aRect.RightCenter() , HDL_RIGHT, 0, 0));
-       rTarget.AddHdl(new SdrCropHdl(aRect.BottomLeft()  , HDL_LWLFT, 0, 0));
-       rTarget.AddHdl(new SdrCropHdl(aRect.BottomCenter(), HDL_LOWER, 0, 0));
-       rTarget.AddHdl(new SdrCropHdl(aRect.BottomRight() , HDL_LWRGT, 0, 0));
+        const Rectangle aOutRect(GetFlyFrame()->Frame().SVRect());
+        const basegfx::B2DRange aTargetRange(
+            aOutRect.Left(), aOutRect.Top(),
+            aOutRect.Right(), aOutRect.Bottom());
+
+        if(!aTargetRange.isEmpty())
+        {
+            const sal_uInt16 nRotation(SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame());
+            const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0));
+            const basegfx::B2DHomMatrix aTargetTransform(
+                basegfx::tools::createRotateAroundCenterKeepAspectRatioStayInsideRange(
+                    aTargetRange,
+                    fRotate));
+            basegfx::B2DPoint aPos;
+            const double fShearX(0.0);
+
+            aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.0);
+            rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), HDL_UPLFT, fShearX, fRotate));
+            aPos = aTargetTransform * basegfx::B2DPoint(0.5, 0.0);
+            rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), HDL_UPPER, fShearX, fRotate));
+            aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.0);
+            rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), HDL_UPRGT, fShearX, fRotate));
+            aPos = aTargetTransform * basegfx::B2DPoint(0.0, 0.5);
+            rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), HDL_LEFT , fShearX, fRotate));
+            aPos = aTargetTransform * basegfx::B2DPoint(1.0, 0.5);
+            rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), HDL_RIGHT, fShearX, fRotate));
+            aPos = aTargetTransform * basegfx::B2DPoint(0.0, 1.0);
+            rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), HDL_LWLFT, fShearX, fRotate));
+            aPos = aTargetTransform * basegfx::B2DPoint(0.5, 1.0);
+            rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), HDL_LOWER, fShearX, fRotate));
+            aPos = aTargetTransform * basegfx::B2DPoint(1.0, 1.0);
+            rTarget.AddHdl(new SdrCropHdl(Point(basegfx::fround(aPos.getX()), basegfx::fround(aPos.getY())), HDL_LWRGT, fShearX, fRotate));
+        }
     }
 }
 
@@ -1007,10 +1085,4 @@ bool SwVirtFlyDrawObj::supportsFullDrag() const
     return SdrVirtObj::supportsFullDrag();
 }
 
-SdrObject* SwVirtFlyDrawObj::getFullDragClone() const
-{
-    // call parent
-    return SdrVirtObj::getFullDragClone();
-}
-
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sw/source/core/inc/dflyobj.hxx b/sw/source/core/inc/dflyobj.hxx
index 4a8274db6a28..0218aa5f020b 100644
--- a/sw/source/core/inc/dflyobj.hxx
+++ b/sw/source/core/inc/dflyobj.hxx
@@ -62,6 +62,10 @@ class SwVirtFlyDrawObj : public SdrVirtObj
 private:
     SwFlyFrame *m_pFlyFrame;
 
+    // RotGrfFlyFrame: Helper to acces sthe rotation angle (in 10th degrees, left-handed)
+    // of a GraphicFrame
+    sal_uInt16 getPossibleRotationFromFraphicFrame() const;
+
 protected:
     // AW: Need own sdr::contact::ViewContact since AnchorPos from parent is
     // not used but something own (top left of new SnapRect minus top left
@@ -106,6 +110,9 @@ public:
     virtual       void       Crop(const Point& rRef, const Fraction& xFact, const Fraction& yFact) override;
     virtual       void       addCropHandles(SdrHdlList& rTarget) const override;
 
+    // FullDrag support
+    virtual SdrObject* getFullDragClone() const override;
+
     const SwFrameFormat *GetFormat() const;
           SwFrameFormat *GetFormat();
 
@@ -122,7 +129,6 @@ public:
 
     // FullDrag support
     virtual bool supportsFullDrag() const override;
-    virtual SdrObject* getFullDragClone() const override;
 };
 
 #endif
diff --git a/sw/source/core/inc/frmtool.hxx b/sw/source/core/inc/frmtool.hxx
index aa278cf6494c..7af857d6d823 100644
--- a/sw/source/core/inc/frmtool.hxx
+++ b/sw/source/core/inc/frmtool.hxx
@@ -72,10 +72,11 @@ bool DrawFillAttributes(
     const SwRegionRects& rPaintRegion,
     OutputDevice& rOut);
 
+// RotGrfFlyFrame: Adapted to rotation
 void paintGraphicUsingPrimitivesHelper(
-        OutputDevice & rOutputDevice,
-        GraphicObject const& rGraphicObj, GraphicAttr const& rGraphicAttr,
-        SwRect const& rAlignedGrfArea);
+    OutputDevice & rOutputDevice,
+    GraphicObject const& rGraphicObj, GraphicAttr const& rGraphicAttr,
+    SwRect const& rAlignedGrfArea);
 
 // method to align rectangle.
 // Created declaration here to avoid <extern> declarations
commit bd16e712524aa02bccaf26c11ba4b0504ffaeecc
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Tue Sep 26 15:41:23 2017 +0200

    RotGrfFlyFrame: Minimal working rotation solution
    
    This version allows rotation (in 10th degrees) and perserves
    it over save/load cycles. Rotation of multiples of 90 degree
    behave close to original except not changing the contained
    Graphic and being adaptable to all kinds of graphic. The
    rotated Graphic is displayed centered and under preserved
    AspectRatio in the available frame space (so no rotation,
    180 degree is identical, 90/-90 is identical with 1:1 ratio
    of the graphic)
    
    Change-Id: I54b3385f709ee0d34a55324aca919dcd2ce0c009

diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index e8e2c2bdd18f..0bcbe33cdb96 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -779,16 +779,36 @@ void paintGraphicUsingPrimitivesHelper(vcl::RenderContext & rOutputDevice,
     // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees
     if(0 != rGraphicAttr.GetRotation())
     {
+        // Fit rotated graphic to center of available space, keeping page ratio:
+        // Adapt scaling ratio of unit object and rotate it
         const double fRotate(static_cast< double >(-rGraphicAttr.GetRotation()) * (M_PI/1800.0));
-        aTargetTransform.translate(-0.5, -0.5);
+        aTargetTransform.scale(1.0, aTargetRange.getHeight() / aTargetRange.getWidth());
         aTargetTransform.rotate(fRotate);
-        aTargetTransform.translate(0.5, 0.5);
-    }
 
-    // needed scale/translate
-    aTargetTransform *= basegfx::tools::createScaleTranslateB2DHomMatrix(
-        aTargetRange.getRange(),
-        aTargetRange.getMinimum());
+        // get the range to see where we are in unit coordinates
+        basegfx::B2DRange aFullRange(0.0, 0.0, 1.0, 1.0);
+        aFullRange.transform(aTargetTransform);
+
+        // detect needed scales in X/Y and choose the smallest for staying inside the
+        // available space while keeping aspect ratio of the source
+        const double fScaleX(aTargetRange.getWidth() / aFullRange.getWidth());
+        const double fScaleY(aTargetRange.getHeight() / aFullRange.getHeight());
+        const double fScaleMin(std::min(fScaleX, fScaleY));
+
+        // TopLeft to zero, then scale, then move to center of available space
+        aTargetTransform.translate(-aFullRange.getMinX(), -aFullRange.getMinY());
+        aTargetTransform.scale(fScaleMin, fScaleMin);
+        aTargetTransform.translate(
+            aTargetRange.getCenterX() - (0.5 * fScaleMin * aFullRange.getWidth()),
+            aTargetRange.getCenterY() - (0.5 * fScaleMin * aFullRange.getHeight()));
+    }
+    else
+    {
+        // just scale/translate needed
+        aTargetTransform *= basegfx::tools::createScaleTranslateB2DHomMatrix(
+            aTargetRange.getRange(),
+            aTargetRange.getMinimum());
+    }
 
     drawinglayer::primitive2d::Primitive2DContainer aContent(1);
     bool bDone(false);
diff --git a/sw/source/uibase/frmdlg/frmmgr.cxx b/sw/source/uibase/frmdlg/frmmgr.cxx
index c01511c4e348..287206837ee0 100644
--- a/sw/source/uibase/frmdlg/frmmgr.cxx
+++ b/sw/source/uibase/frmdlg/frmmgr.cxx
@@ -47,7 +47,12 @@
 using namespace ::com::sun::star;
 
 static sal_uInt16 aFrameMgrRange[] = {
-                            RES_FRMATR_BEGIN, RES_FRMATR_END-1,
+                            RES_FRMATR_BEGIN, RES_FRMATR_END-1, // 87-129
+
+                            // RotGrfFlyFrame: Support here, but seems not to be
+                            // added in range of m_pOwnSh->GetFlyFrameAttr result
+                            // (see below). Tried to find, but could not identify
+                            RES_GRFATR_ROTATION, RES_GRFATR_ROTATION, // 132
 
                             //UUUU FillAttribute support
                             XATTR_FILL_FIRST, XATTR_FILL_LAST,
@@ -570,13 +575,17 @@ void SwFlyFrameAttrMgr::SetHeightSizeType( SwFrameSize eType )
     m_aSet.Put( aSize );
 }
 
-void SwFlyFrameAttrMgr::SetRotation(sal_uInt32 nOld, sal_uInt32 nNew, Size aUnrotatedSize)
+void SwFlyFrameAttrMgr::SetRotation(sal_uInt16 nOld, sal_uInt16 nNew, const Size& rUnrotatedSize)
 {
-    // RotGrfFlyFrame: Central handling of real change of rotation here. Adaption of pos/size
-    // may be wanted in the future
+    // RotGrfFlyFrame: Central handling of real change of rotation here, all adaptions use this.
+    // Adaption of pos/size may be wanted in the future. Already tried to keep last SIze in
+    // UnrotatedSize in the SwRotationGrf Item, but this will lead to various problems. Also tried
+    // to use m_aSet.Put(...) as in other methods (also read methods for Rotation/UnrotatedSize) but
+    // somehow the needed ID (RES_GRFATR_ROTATION) is *not* in the SfxItemSet of the Frame, so for
+    // now set directly. Undo/Redo is preserved by AttributeChange
     if(nOld != nNew)
     {
-        m_pOwnSh->SetAttrItem(SwRotationGrf(static_cast<sal_uInt16>(nNew), aUnrotatedSize));
+        m_pOwnSh->SetAttrItem(SwRotationGrf(nNew, rUnrotatedSize));
     }
 }
 
diff --git a/sw/source/uibase/inc/frmmgr.hxx b/sw/source/uibase/inc/frmmgr.hxx
index 255eedf18d06..56cbaa5531f4 100644
--- a/sw/source/uibase/inc/frmmgr.hxx
+++ b/sw/source/uibase/inc/frmmgr.hxx
@@ -93,7 +93,7 @@ public:
     void                SetHeightSizeType(SwFrameSize eType);
 
     // rotation
-    void                SetRotation(sal_uInt32 nOld, sal_uInt32 nNew, Size aUnrotatedSize);
+    void                SetRotation(sal_uInt16 nOld, sal_uInt16 nNew, const Size& rUnrotatedSize);
 
     // space to content
     void                SetLRSpace( long nLeft  = LONG_MAX,
diff --git a/sw/source/uibase/shells/grfsh.cxx b/sw/source/uibase/shells/grfsh.cxx
index a46438b7f19c..d5906887cb66 100644
--- a/sw/source/uibase/shells/grfsh.cxx
+++ b/sw/source/uibase/shells/grfsh.cxx
@@ -866,13 +866,6 @@ void SwGrfShell::GetAttrState(SfxItemSet &rSet)
 void SwGrfShell::ExecuteRotation(SfxRequest &rReq)
 {
     // RotGrfFlyFrame: Modify rotation attribute instead of manipulating the graphic
-    SwWrtShell& rShell = GetShell();
-    SfxItemSet aSet( rShell.GetAttrPool(),
-        RES_GRFATR_ROTATION, RES_GRFATR_ROTATION,
-        SID_ATTR_TRANSFORM_ANGLE, SID_ATTR_TRANSFORM_ANGLE,
-        0, 0 );
-    rShell.GetCurAttr( aSet );
-    const SwRotationGrf& rRotation = static_cast<const SwRotationGrf&>(aSet.Get(RES_GRFATR_ROTATION));
     sal_uInt16 aRotation(0);
 
     if (rReq.GetSlot() == SID_ROTATE_GRAPHIC_LEFT)
@@ -886,22 +879,23 @@ void SwGrfShell::ExecuteRotation(SfxRequest &rReq)
 
     if (rReq.GetSlot() == SID_ROTATE_GRAPHIC_RESET || 0 != aRotation)
     {
-        rShell.StartAllAction();
-        rShell.StartUndo(UNDO_START);
+        SwWrtShell& rShell = GetShell();
+        SfxItemSet aSet( rShell.GetAttrPool(), RES_GRFATR_ROTATION, RES_GRFATR_ROTATION, 0, 0 );
+        rShell.GetCurAttr( aSet );
+        const SwRotationGrf& rRotation = static_cast<const SwRotationGrf&>(aSet.Get(RES_GRFATR_ROTATION));
+        SwFlyFrameAttrMgr aMgr(false, &rShell, rShell.IsFrameSelected() ? Frmmgr_Type::NONE : Frmmgr_Type::GRF);
 
+        // RotGrfFlyFrame: Possible rotation change here, SwFlyFrameAttrMgr aMgr is available
         if (rReq.GetSlot() == SID_ROTATE_GRAPHIC_RESET)
         {
-            rShell.SetAttrItem(SwRotationGrf(0, rRotation.GetUnrotatedSize()));
+            aMgr.SetRotation(rRotation.GetValue(), 0, rRotation.GetUnrotatedSize());
         }
         else if(0 != aRotation)
         {
-            sal_uInt16 aNewRotation((aRotation + rRotation.GetValue()) % 3600);
+            const sal_uInt16 aNewRotation((aRotation + rRotation.GetValue()) % 3600);
 
-            rShell.SetAttrItem(SwRotationGrf(aNewRotation, rRotation.GetUnrotatedSize()));
+            aMgr.SetRotation(rRotation.GetValue(), aNewRotation, rRotation.GetUnrotatedSize());
         }
-
-        rShell.EndUndo(UNDO_END);
-        rShell.EndAllAction();
     }
 }
 
commit 3db7fbfe024fbc9324afaba3a37cfae20cbf17c9
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Fri Sep 22 15:28:33 2017 +0200

    RotGrfFlyFrame: Initial adaptions
    
    To allow free rotation of Graphic FlyFrames in Writer,
    several adaptions are necessary. This change takes care
    of all needed changes to internally support a freely
    definable rotation angle for that case. Save/Load round
    trip is working, the graphic does no longer get modified
    and added in 90-degree-changed state to the object, the
    original will be preserved. Support for needed slot in
    core/ui is implemented. Rotation can be applied from
    Menus/Toolbars in the known 90/180 degree steps. Added
    a slot/Button/command to reset rotation in these cases.
    Added support in Sidebar to rotate using the rotation
    wheel and/or numeric field. These fields and support added
    to Image TabPage, too, fully functional.
    Missing now is a solution for displaying the rotated
    Graphic. For now, it just gets rotated, but this will not
    be the final state of this change.
    
    Change-Id: I6f3b85ebb5be2b4ad3311c536d54f27a37a494e7
    365287ecd6525b1972e8436d61332f7121d88649
    RotGrfFlyFrame: Linux build adaptions

diff --git a/include/svx/svxids.hrc b/include/svx/svxids.hrc
index 340fc610cc11..af989bc60a2a 100644
--- a/include/svx/svxids.hrc
+++ b/include/svx/svxids.hrc
@@ -987,6 +987,7 @@
 #define SID_ROTATE_GRAPHIC_LEFT                         ( SID_SVX_START + 1121 )
 #define SID_ROTATE_GRAPHIC_RIGHT                        ( SID_SVX_START + 1122 )
 #define SID_MENU_MANAGE_GRAPHIC                         ( SID_SVX_START + 1123 )
+#define SID_ROTATE_GRAPHIC_RESET                        ( SID_SVX_START + 1092 ) /* RotGrfFlyFrame: new slot */
 
 // new slots for panels
 #define SID_ATTR_FILL_TRANSPARENCE                      ( SID_SVX_START + 1124 )
diff --git a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
index 1a5d1c3d0b6d..3d5c25393b19 100644
--- a/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
+++ b/officecfg/registry/data/org/openoffice/Office/UI/WriterCommands.xcu
@@ -918,6 +918,14 @@
           <value>1</value>
         </prop>
       </node>
+      <node oor:name=".uno:RotateReset" oor:op="replace">
+        <prop oor:name="Label" oor:type="xs:string">
+          <value xml:lang="en-US">Reset R~otation</value>
+        </prop>
+        <prop oor:name="Properties" oor:type="xs:int">
+          <value>1</value>
+        </prop>
+      </node>
       <node oor:name=".uno:NewHtmlDoc" oor:op="replace">
         <prop oor:name="Label" oor:type="xs:string">
           <value xml:lang="en-US">Create ~HTML Document</value>
diff --git a/svx/sdi/svx.sdi b/svx/sdi/svx.sdi
index f9667ebcff0c..9754bd41cc50 100644
--- a/svx/sdi/svx.sdi
+++ b/svx/sdi/svx.sdi
@@ -4436,6 +4436,23 @@ SfxVoidItem RotateRight SID_ROTATE_GRAPHIC_RIGHT
     GroupId = GID_GRAPHIC;
 ]
 
+SfxVoidItem RotateReset SID_ROTATE_GRAPHIC_RESET
+
+[
+    AutoUpdate = FALSE,
+    FastCall = FALSE,
+    ReadOnlyDoc = TRUE,
+    Toggle = FALSE,
+    Container = FALSE,
+    RecordAbsolute = FALSE,
+    RecordPerSet;
+
+    AccelConfig = TRUE,
+    MenuConfig = TRUE,
+    ToolBoxConfig = TRUE,
+    GroupId = GID_GRAPHIC;
+]
+
 SfxVoidItem Crop SID_OBJECT_CROP
 ()
 [
diff --git a/svx/source/sidebar/possize/PosSizePropertyPanel.cxx b/svx/source/sidebar/possize/PosSizePropertyPanel.cxx
index 103d226d2616..189366cdc86b 100644
--- a/svx/source/sidebar/possize/PosSizePropertyPanel.cxx
+++ b/svx/source/sidebar/possize/PosSizePropertyPanel.cxx
@@ -276,6 +276,7 @@ void PosSizePropertyPanel::HandleContextChange(
 
         case CombinedEnumContext(Application_WriterVariants, Context_Graphic):
             bShowFlip = true;
+            bShowAngle = true; // RotGrfFlyFrame: Writer FlyFrames for Graphics now support angle
             break;
 
         case CombinedEnumContext(Application_Calc, Context_Draw):
diff --git a/sw/sdi/_grfsh.sdi b/sw/sdi/_grfsh.sdi
index bf8270c74bef..2e326c30fe78 100644
--- a/sw/sdi/_grfsh.sdi
+++ b/sw/sdi/_grfsh.sdi
@@ -87,6 +87,20 @@ interface BaseTextGraphic
         DisableFlags="SW_DISABLE_ON_PROTECTED_CURSOR";
     ]
 
+    SID_ROTATE_GRAPHIC_RESET
+    [
+        ExecMethod = ExecuteRotation ;
+        StateMethod = GetAttrStateForRotation ;
+        DisableFlags="SW_DISABLE_ON_PROTECTED_CURSOR";
+    ]
+
+    SID_ATTR_TRANSFORM_ANGLE
+    [
+        ExecMethod = ExecuteRotation ;
+        StateMethod = GetAttrStateForRotation ;
+        DisableFlags="SW_DISABLE_ON_PROTECTED_CURSOR";
+    ]
+
     SID_OBJECT_CROP
     [
         ExecMethod = Execute ;
diff --git a/sw/source/core/doc/notxtfrm.cxx b/sw/source/core/doc/notxtfrm.cxx
index 8578e458fea5..e8e2c2bdd18f 100644
--- a/sw/source/core/doc/notxtfrm.cxx
+++ b/sw/source/core/doc/notxtfrm.cxx
@@ -774,10 +774,21 @@ void paintGraphicUsingPrimitivesHelper(vcl::RenderContext & rOutputDevice,
     const basegfx::B2DRange aTargetRange(
         rAlignedGrfArea.Left(), rAlignedGrfArea.Top(),
         rAlignedGrfArea.Right(), rAlignedGrfArea.Bottom());
-    const basegfx::B2DHomMatrix aTargetTransform(
-        basegfx::tools::createScaleTranslateB2DHomMatrix(
-            aTargetRange.getRange(),
-            aTargetRange.getMinimum()));
+    basegfx::B2DHomMatrix aTargetTransform;
+
+    // RotGrfFlyFrame: Take rotation into account. Rotation is in 10th degrees
+    if(0 != rGraphicAttr.GetRotation())
+    {
+        const double fRotate(static_cast< double >(-rGraphicAttr.GetRotation()) * (M_PI/1800.0));
+        aTargetTransform.translate(-0.5, -0.5);
+        aTargetTransform.rotate(fRotate);
+        aTargetTransform.translate(0.5, 0.5);
+    }
+
+    // needed scale/translate
+    aTargetTransform *= basegfx::tools::createScaleTranslateB2DHomMatrix(
+        aTargetRange.getRange(),
+        aTargetRange.getMinimum());
 
     drawinglayer::primitive2d::Primitive2DContainer aContent(1);
     bool bDone(false);
diff --git a/sw/source/ui/frmdlg/frmpage.cxx b/sw/source/ui/frmdlg/frmpage.cxx
index 8b7a175b82db..b2ef9ae9294b 100644
--- a/sw/source/ui/frmdlg/frmpage.cxx
+++ b/sw/source/ui/frmdlg/frmpage.cxx
@@ -2380,6 +2380,12 @@ SwGrfExtPage::SwGrfExtPage(vcl::Window *pParent, const SfxItemSet &rSet)
     get(m_pBmpWin, "preview");
     m_pBmpWin->SetBitmapEx(get<FixedImage>("fallback")->GetImage().GetBitmapEx());
 
+    // RotGrfFlyFrame: Need Angle and RotateControls now
+    get(m_pFlAngle, "FL_ANGLE");
+    get(m_pNfAngle, "NF_ANGLE");
+    get(m_pCtlAngle, "CTL_ANGLE");
+    m_pCtlAngle->SetLinkedField( m_pNfAngle, 2 );
+
     SetExchangeSupport();
     m_pMirrorHorzBox->SetClickHdl( LINK(this, SwGrfExtPage, MirrorHdl));
     m_pMirrorVertBox->SetClickHdl( LINK(this, SwGrfExtPage, MirrorHdl));
@@ -2403,6 +2409,12 @@ void SwGrfExtPage::dispose()
     m_pBmpWin.clear();
     m_pConnectED.clear();
     m_pBrowseBT.clear();
+
+    // RotGrfFlyFrame: Support RotationAngle
+    m_pFlAngle.clear();
+    m_pNfAngle.clear();
+    m_pCtlAngle.clear();
+
     SfxTabPage::dispose();
 }
 
@@ -2424,6 +2436,17 @@ void SwGrfExtPage::Reset(const SfxItemSet *rSet)
         m_pConnectED->SetReadOnly(false);
     }
 
+    // RotGrfFlyFrame: Get RotationAngle and set at control
+    if(SfxItemState::SET == rSet->GetItemState( SID_ATTR_TRANSFORM_ANGLE, false, &pItem))
+    {
+        m_pCtlAngle->SetRotation(static_cast<const SfxInt32Item*>(pItem)->GetValue());
+    }
+    else
+    {
+        m_pCtlAngle->SetRotation(0);
+    }
+    m_pCtlAngle->SaveValue();
+
     ActivatePage(*rSet);
 }
 
@@ -2551,6 +2574,14 @@ bool SwGrfExtPage::FillItemSet( SfxItemSet *rSet )
         rSet->Put( SvxBrushItem( aGrfName, aFilterName, GPOS_LT,
                                 SID_ATTR_GRAF_GRAPHIC ));
     }
+
+    // RotGrfFlyFrame: Safe rotation if modified
+    if(m_pCtlAngle->IsValueModified())
+    {
+        rSet->Put(SfxInt32Item(GetWhich(SID_ATTR_TRANSFORM_ANGLE), m_pCtlAngle->GetRotation()));
+        bModified = true;
+    }
+
     return bModified;
 }
 
diff --git a/sw/source/uibase/frmdlg/frmmgr.cxx b/sw/source/uibase/frmdlg/frmmgr.cxx
index bb7bad68a414..c01511c4e348 100644

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list