[Libreoffice-commits] core.git: Branch 'feature/RotGrfFlyFrame' - 683 commits - accessibility/inc accessibility/source android/source avmedia/Library_avmedia.mk avmedia/Module_avmedia.mk avmedia/source basctl/inc basctl/source basctl/uiconfig basegfx/inc basegfx/source basegfx/test basic/inc basic/qa basic/source bean/native binaryurp/source bin/find-most-common-warn-messages.py bin/get-bugzilla-attachments-by-mimetype bin/lint-ui.py bin/update bin/update_pch bridges/CustomTarget_gcc3_ios.mk bridges/Library_cpp_uno.mk bridges/Module_bridges.mk bridges/source canvas/source canvas/workben chart2/inc chart2/qa chart2/source cli_ure/qa cli_ure/source codemaker/source comphelper/inc comphelper/source compilerplugins/clang compilerplugins/Makefile-clang.mk compilerplugins/Makefile.mk config_host.mk.in configmgr/inc configmgr/source configure.ac connectivity/inc connectivity/source cppcanvas/inc cppcanvas/source cppuhelper/source cppu/qa cpputools/source cui/inc cui/source cui/uiconfig dbaccess/inc dbac cess/Module_dbaccess.mk dbaccess/source dbaccess/uiconfig dbaccess/win32 desktop/inc desktop/qa desktop/source desktop/test desktop/win32 distro-configs/Jenkins distro-configs/LibreOfficeiOS.conf download.lst drawinglayer/inc drawinglayer/source dtrans/source dtrans/test editeng/inc editeng/source embeddedobj/source embedserv/source emfio/inc emfio/source eventattacher/source extensions/source extensions/test external/beanshell external/coinmp external/curl external/firebird external/hunspell external/libabw external/libcdr external/libebook external/libetonyek external/libexttextcat external/libfreehand external/libmspub external/libmwaw external/libodfgen external/liborcus external/libpagemaker external/libpng external/libqxp external/libstaroffice external/libvisio external/libwpd external/libwpg external/libwps external/libxslt external/libzmf external/more_fonts external/mythes external/openldap external/owncloud-android-lib external/pdfium external/xmlsec extras/source filter/ Library_graphicfilter.mk filter/qa filter/source forms/inc forms/source formula/source formula/uiconfig fpicker/source framework/inc framework/qa framework/source .git-hooks/pre-commit helpcompiler/inc helpcompiler/source helpcontent2 hwpfilter/inc hwpfilter/source i18npool/inc i18npool/qa i18npool/source i18nutil/source icon-themes/breeze icon-themes/breeze_dark icon-themes/breeze_svg icon-themes/crystal icon-themes/elementary icon-themes/galaxy icon-themes/hicontrast icon-themes/oxygen icon-themes/sifr icon-themes/sifr_dark icon-themes/sifr_svg icon-themes/tango idlc/source include/basegfx include/comphelper include/cppuhelper include/drawinglayer include/editeng include/formula include/i18nlangtag include/i18nutil include/LibreOfficeKit include/o3tl include/oox include/sal include/sfx2 include/svl include/svtools include/svx include/systools include/toolkit include/tools include/unotools include/vbahelper include/vcl include/xmloff ios/CustomTarget_iOS.mk ios/CustomTarget_LibreOf ficeLight_app.mk ios/CustomTarget_Lo_Xcconfig.mk ios/CustomTarget_Prototype_app.mk ios/DISCLAIMER_WARNING ios/experimental ios/.gitignore ios/LibreOfficeKit ios/LibreOfficeLight ios/loApp.xcconfig.in ios/loKit.xcconfig.in ios/lo.xcconfig.in ios/Module_ios.mk io/source ios/README javaunohelper/source jvmfwk/plugins jvmfwk/source l10ntools/source libreofficekit/Executable_gtktiledviewer.mk libreofficekit/qa libreofficekit/source lingucomponent/source linguistic/source lotuswordpro/inc lotuswordpro/source Makefile.in mysqlc/source odk/examples odk/source offapi/com officecfg/README officecfg/registry officecfg/util oox/inc oox/source opencl/source package/inc package/source postprocess/CustomTarget_fontconfig.mk postprocess/CustomTarget_images.mk postprocess/Module_postprocess.mk postprocess/Package_fontconfig.mk pyuno/Module_pyuno.mk pyuno/PythonTest_pytests.mk pyuno/qa pyuno/source qadevOOo/runner qadevOOo/tests readlicense_oo/docs readlicense_oo/license README.md reportdesign/inc re portdesign/Library_rptui.mk reportdesign/source reportdesign/util Repository.mk sal/inc sal/osl sal/qa sal/rtl sal/textenc sax/source scaddins/source sc/inc sc/qa scripting/source sc/source sc/uiconfig sdext/inc sdext/source sd/inc sd/qa sd/source sd/uiconfig sd/xsl setup_native/source sfx2/classification sfx2/inc sfx2/qa sfx2/sdi sfx2/source shell/inc shell/qa shell/source slideshow/inc slideshow/source slideshow/test solenv/bin solenv/CompilerTest_compilerplugins_clang.mk solenv/gbuild solenv/gdb solenv/inc soltools/cpp sot/inc sot/qa sot/source starmath/inc starmath/qa starmath/source starmath/uiconfig stoc/source stoc/test svgio/inc svgio/source svl/inc svl/qa svl/source svtools/inc svtools/langsupport svtools/Library_svt.mk svtools/qa svtools/source svtools/uiconfig svtools/UIConfig_svt.mk svx/inc svx/Library_svx.mk svx/sdi svx/source svx/uiconfig svx/UIConfig_svx.mk svx/util svx/workben sw/CppunitTest_sw_rtfimport.mk sw/CppunitTest_sw_uiwriter.mk swext/mediawiki sw/inc sw/qa s w/sdi sw/source sw/uiconfig sw/UIConfig_sglobal.mk sysui/CustomTarget_solaris.mk test/source toolkit/source tools/inc tools/qa tools/source ucbhelper/source ucb/Library_ucpimage.mk ucb/source uitest/libreoffice unodevtools/source unotools/inc unotools/qa unotools/source unoxml/inc unoxml/source uui/inc uui/source vbahelper/inc vbahelper/source vcl/android vcl/backendtest vcl/Executable_fodpfuzzer.mk vcl/Executable_fodsfuzzer.mk vcl/headless vcl/inc vcl/Library_vcl.mk vcl/Module_vcl.mk vcl/opengl vcl/osx vcl/qa vcl/quartz vcl/README.scheduler vcl/source vcl/unx vcl/win vcl/workben winaccessibility/Library_uacccom.mk winaccessibility/Library_winaccessibility.mk winaccessibility/source wizards/com wizards/source writerfilter/inc writerfilter/source writerperfect/Module_writerperfect.mk writerperfect/qa writerperfect/source writerperfect/UITest_writerperfect_epubexport.mk xmlhelp/source xmlhelp/util xmloff/inc xmloff/source xmlscript/inc xmlscript/source xmlscript/test xmlsecurity/inc x mlsecurity/qa xmlsecurity/source xmlsecurity/workben

Armin Le Grand Armin.Le.Grand at cib.de
Thu Oct 5 20:02:52 UTC 2017


Rebased ref, commits from common ancestor:
commit 39d207272447af28a471a5d00b4cefa0b5d7df67
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 f437c4274f06..55e05d73e57f 100644
--- a/sw/source/core/draw/dview.cxx
+++ b/sw/source/core/draw/dview.cxx
@@ -829,11 +829,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 c83a4a76b3adcea486e391f891f3bd0065a53764
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 26936aff2e5c..e26fb922f5b6 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 3d7ded0a7fe9..cd6953312565 100644
--- a/include/svx/svdobj.hxx
+++ b/include/svx/svdobj.hxx
@@ -410,6 +410,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 a6223975572d..c6d626e1305f 100644
--- a/include/svx/svdovirt.hxx
+++ b/include/svx/svdovirt.hxx
@@ -68,6 +68,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/include/svx/svxids.hrc b/include/svx/svxids.hrc
index 79ebc50726c1..8d0e22a22179 100644
--- a/include/svx/svxids.hrc
+++ b/include/svx/svxids.hrc
@@ -919,7 +919,7 @@
 #define SID_ROTATE_GRAPHIC_LEFT                         ( SID_SVX_START + 1121 )
 #define SID_ROTATE_GRAPHIC_RIGHT                        ( SID_SVX_START + 1122 )
 #define SID_ROTATE_GRAPHIC_180                          ( SID_SVX_START + 1123 )
-#define SID_ROTATE_GRAPHIC_RESET                        ( SID_SVX_START + 1092 ) /* RotGrfFlyFrame: new slot */
+#define SID_ROTATE_GRAPHIC_RESET                        ( SID_SVX_START + 1092 ) /* RotGrfFlyFrame: */
 
 // new slots for panels
 #define SID_ATTR_FILL_TRANSPARENCE                      ( SID_SVX_START + 1124 )
diff --git a/svx/source/svdraw/svddrgmt.cxx b/svx/source/svdraw/svddrgmt.cxx
index 3348579bd508..a00528f61af8 100644
--- a/svx/source/svdraw/svddrgmt.cxx
+++ b/svx/source/svdraw/svddrgmt.cxx
@@ -2097,18 +2097,28 @@ bool SdrDragRotate::BeginSdrDrag()
 {
     SdrHdl* pH=GetHdlList().GetHdl(SdrHdlKind::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 tools::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 73a79d4bb983..61286258cc0f 100644
--- a/svx/source/svdraw/svdmrkv.cxx
+++ b/svx/source/svdraw/svdmrkv.cxx
@@ -658,14 +658,22 @@ void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell)
         const size_t nMarkCount=GetMarkedObjectCount();
         bool bStdDrag=meDragMode==SdrDragMode::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 = SdrDragMode::Rotate == meDragMode && mpMarkedObj->HasLimitedRotation();
+            }
         }
 
         bool bFrmHdl=ImpIsFrameHandles();
@@ -831,27 +839,59 @@ void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell)
                 }
                 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(),SdrHdlKind::UpperLeft));
+                        maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), SdrHdlKind::UpperLeft));
                     }
                     else if (!bStdDrag && (bWdt0 || bHgt0))
                     {
-                        maHdlList.AddHdl(new SdrHdl(aRect.TopLeft()    ,SdrHdlKind::UpperLeft));
-                        maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(),SdrHdlKind::LowerRight));
+                        maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), SdrHdlKind::UpperLeft));
+                        maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(), SdrHdlKind::LowerRight));
                     }
                     else
                     {
-                        if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopLeft()     ,SdrHdlKind::UpperLeft));
-                        if (          !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopCenter()   ,SdrHdlKind::Upper));
-                        if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.TopRight()    ,SdrHdlKind::UpperRight));
-                        if (!bWdt0          ) maHdlList.AddHdl(new SdrHdl(aRect.LeftCenter()  ,SdrHdlKind::Left ));
-                        if (!bWdt0          ) maHdlList.AddHdl(new SdrHdl(aRect.RightCenter() ,SdrHdlKind::Right));
-                        if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomLeft()  ,SdrHdlKind::LowerLeft));
-                        if (          !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomCenter(),SdrHdlKind::Lower));
-                        if (!bWdt0 && !bHgt0) maHdlList.AddHdl(new SdrHdl(aRect.BottomRight() ,SdrHdlKind::LowerRight));
+                        if (!bWdt0 && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.TopLeft(), SdrHdlKind::UpperLeft));
+                        }
+
+                        if (!bLimitedRotation && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.TopCenter(), SdrHdlKind::Upper));
+                        }
+
+                        if (!bWdt0 && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.TopRight(), SdrHdlKind::UpperRight));
+                        }
+
+                        if (!bLimitedRotation && !bWdt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.LeftCenter(), SdrHdlKind::Left ));
+                        }
+
+                        if (!bLimitedRotation && !bWdt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.RightCenter(), SdrHdlKind::Right));
+                        }
+
+                        if (!bWdt0 && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.BottomLeft(), SdrHdlKind::LowerLeft));
+                        }
+
+                        if (!bLimitedRotation && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.BottomCenter(), SdrHdlKind::Lower));
+                        }
+
+                        if (!bWdt0 && !bHgt0)
+                        {
+                            maHdlList.AddHdl(new SdrHdl(aRect.BottomRight(), SdrHdlKind::LowerRight));
+                        }
                     }
                 }
             }
@@ -945,7 +985,10 @@ void SdrMarkView::SetMarkHandles(SfxViewShell* pOtherShell)
         }
 
         // 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 f5f3f269f866..b2dd3a2fc6c8 100644
--- a/svx/source/svdraw/svdobj.cxx
+++ b/svx/source/svdraw/svdobj.cxx
@@ -931,6 +931,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 7c9f54e35bd8..d7145be8f93a 100644
--- a/svx/source/svdraw/svdovirt.cxx
+++ b/svx/source/svdraw/svdovirt.cxx
@@ -166,6 +166,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 0775d14cd852..1141a4ea9812 100644
--- a/sw/inc/fesh.hxx
+++ b/sw/inc/fesh.hxx
@@ -505,6 +505,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..8451eae60eba 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="SfxDisableFlags::SwOnProtectedCursor";
+    ]
 }
 
diff --git a/sw/source/core/draw/dflyobj.cxx b/sw/source/core/draw/dflyobj.cxx
index 6a21d0eb9d71..29e5e4a94715 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>
@@ -354,6 +355,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
@@ -477,7 +536,9 @@ void SwVirtFlyDrawObj::TakeObjInfo( SdrObjTransformInfoRec& rInfo ) const
     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   =
@@ -924,7 +985,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());
@@ -939,6 +1000,7 @@ sal_uInt16 SwVirtFlyDrawObj::getPossibleRotationFromFraphicFrame() const
             const SwAttrSet& rSet = pGrfNd->GetSwAttrSet();
             const SwRotationGrf& rRotation = rSet.GetRotationGrf();
 
+            rSize = rRotation.GetUnrotatedSize();
             nRetval = rRotation.GetValue();
         }
     }
@@ -951,25 +1013,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 tools::Rectangle aTmpOutRect(GetFlyFrame()->Frame().SVRect());
-            const basegfx::B2DRange aTargetRange(
-                aTmpOutRect.Left(), aTmpOutRect.Top(),
-                aTmpOutRect.Right(), aTmpOutRect.Bottom());
-            const basegfx::B2DHomMatrix aTargetTransform(
-                basegfx::utils::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::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange(
+                aTargetRange,
+                fRotate));
 
-            pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon());
-        }
+        pRetval->TRSetBaseGeometry(aTargetTransform, basegfx::B2DPolyPolygon());
     }
 
     return pRetval;
@@ -987,7 +1043,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::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange(
diff --git a/sw/source/core/draw/dview.cxx b/sw/source/core/draw/dview.cxx
index 5bf7304acf39..f437c4274f06 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>
@@ -814,6 +815,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();
@@ -826,10 +829,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
@@ -847,6 +858,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;
+                    }
                 }
             }
         }
@@ -874,6 +892,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 5ed4bdae28a8..27893c02fae6 100644
--- a/sw/source/core/frmedt/feshview.cxx
+++ b/sw/source/core/frmedt/feshview.cxx
@@ -1161,6 +1161,29 @@ bool SwFEShell::IsObjSelected( const SdrObject& rObj ) const
         return Imp()->GetDrawView()->IsObjMarked( &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 528edc8aff39..8766b7980ebc 100644
--- a/sw/source/core/inc/dflyobj.hxx
+++ b/sw/source/core/inc/dflyobj.hxx
@@ -60,7 +60,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
@@ -77,6 +77,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() override;
@@ -105,6 +107,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;
@@ -122,6 +125,9 @@ public:
     virtual bool       HasMacro() const override;
     virtual SdrObject* CheckMacroHit       (const SdrObjMacroHitRec& rRec) const override;
     virtual Pointer    GetMacroPointer     (const SdrObjMacroHitRec& rRec) 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 b4956cfae92b..a08f441f948b 100644
--- a/sw/source/uibase/frmdlg/frmmgr.cxx
+++ b/sw/source/uibase/frmdlg/frmmgr.cxx
@@ -577,9 +577,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 29251d3dc5b2..01fc01acb9c3 100644
--- a/sw/source/uibase/shells/grfsh.cxx
+++ b/sw/source/uibase/shells/grfsh.cxx
@@ -123,6 +123,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(SdrDragMode::Move);
+                }
+                else
+                {
+                    rSh.SetDragMode(SdrDragMode::Rotate);
+                }
+
+                GetView().FlipDrawRotate();
+            }
+        }
+        break;
+
         case SID_TWAIN_TRANSFER:
         {
             GetView().ExecuteScan( rReq );
@@ -721,6 +742,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 c1ba2219af1b..6494546daebd 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:toolbaritem xlink:href=".uno:RotateLeft"/>
  <toolbar:toolbaritem xlink:href=".uno:RotateRight"/>
+ <toolbar:toolbaritem xlink:href=".uno:ToggleObjectRotateMode"/>
  <toolbar:toolbaritem xlink:href=".uno:Rotate180" toolbar:visible="false"/>
  <toolbar:toolbaritem xlink:href=".uno:RotateReset" toolbar:visible="false"/>
  <toolbar:toolbarseparator/>
commit 40539b42797b83e21c1ad28ab9923c79a016fda5
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 358085bd2760..6a21d0eb9d71 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>
@@ -958,10 +959,10 @@ SdrObject* SwVirtFlyDrawObj::getFullDragClone() const
         if(0 != nRotation)
         {
             const double fRotate(static_cast< double >(-nRotation) * (M_PI/1800.0));
-            const tools::Rectangle aOutRect(GetFlyFrame()->Frame().SVRect());
+            const tools::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::utils::createRotateAroundCenterKeepAspectRatioStayInsideRange(
                     aTargetRange,
@@ -979,10 +980,10 @@ void SwVirtFlyDrawObj::addCropHandles(SdrHdlList& rTarget) const
     // RotGrfFlyFrame: Adapt to possible rotated Graphic contained in FlyFrame
     if(GetFlyFrame()->Frame().HasArea())
     {
-        const tools::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/source/core/layout/paintfrm.cxx.orig b/sw/source/core/layout/paintfrm.cxx.orig
new file mode 100644
index 000000000000..351ac1a8ba35
--- /dev/null
+++ b/sw/source/core/layout/paintfrm.cxx.orig
@@ -0,0 +1,7565 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <vcl/lazydelete.hxx>
+#include <sfx2/docfile.hxx>
+#include <sfx2/progress.hxx>
+#include <editeng/brushitem.hxx>
+#include <editeng/prntitem.hxx>
+#include <editeng/boxitem.hxx>
+#include <editeng/shaditem.hxx>
+#include <svx/framelink.hxx>
+#include <drawdoc.hxx>
+#include <tgrditem.hxx>
+#include <calbck.hxx>
+#include <fmtsrnd.hxx>
+#include <fmtclds.hxx>
+#include <strings.hrc>
+#include <swmodule.hxx>
+#include <rootfrm.hxx>
+#include <pagefrm.hxx>
+#include <section.hxx>
+#include <sectfrm.hxx>
+#include <viewimp.hxx>
+#include <dflyobj.hxx>
+#include <flyfrm.hxx>
+#include <viewopt.hxx>
+#include <dview.hxx>
+#include <dcontact.hxx>
+#include <txtfrm.hxx>
+#include <ftnfrm.hxx>
+#include <tabfrm.hxx>
+#include <rowfrm.hxx>
+#include <cellfrm.hxx>
+#include <notxtfrm.hxx>
+#include <layact.hxx>
+#include <pagedesc.hxx>
+#include <ptqueue.hxx>
+#include <noteurl.hxx>
+#include <virtoutp.hxx>
+#include <lineinfo.hxx>
+#include <dbg_lay.hxx>
+#include <docsh.hxx>
+#include <svx/svdogrp.hxx>
+#include <sortedobjs.hxx>
+#include <EnhancedPDFExportHelper.hxx>
+#include <bodyfrm.hxx>
+#include <hffrm.hxx>
+#include <colfrm.hxx>
+#include <svx/sdr/contact/viewobjectcontactredirector.hxx>
+#include <svx/sdr/contact/viewobjectcontact.hxx>
+#include <svx/sdr/contact/viewcontact.hxx>
+#include <DocumentSettingManager.hxx>
+#include <IDocumentDeviceAccess.hxx>
+
+#include <ndole.hxx>
+#include <PostItMgr.hxx>
+#include <FrameControlsManager.hxx>
+#include <vcl/settings.hxx>
+
+#include <svx/sdr/attribute/sdrallfillattributeshelper.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
+
+#include <svtools/borderhelper.hxx>
+
+#include "bitmaps.hlst"
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <drawinglayer/primitive2d/discreteshadowprimitive2d.hxx>
+#include <drawinglayer/primitive2d/maskprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textprimitive2d.hxx>
+#include <drawinglayer/primitive2d/textlayoutdevice.hxx>
+#include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
+#include <svx/unoapi.hxx>
+#include <svx/framelinkarray.hxx>
+#include <comphelper/sequence.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/color/bcolortools.hxx>
+
+#include <memory>
+#include <vector>
+#include <algorithm>
+#include <wrtsh.hxx>
+#include <edtwin.hxx>
+#include <view.hxx>
+#include <paintfrm.hxx>
+#include <o3tl/typed_flags_set.hxx>
+
+#include <vcl/BitmapTools.hxx>
+
+#define COL_NOTES_SIDEPANE                  RGB_COLORDATA(230,230,230)
+#define COL_NOTES_SIDEPANE_BORDER           RGB_COLORDATA(200,200,200)
+#define COL_NOTES_SIDEPANE_SCROLLAREA       RGB_COLORDATA(230,230,220)
+
+using namespace ::editeng;
+using namespace ::com::sun::star;
+using ::drawinglayer::primitive2d::BorderLinePrimitive2D;
+using ::drawinglayer::primitive2d::BorderLine;
+using std::pair;
+using std::make_pair;
+
+struct SwPaintProperties;
+
+//other subsidiary lines enabled?
+#define IS_SUBS (!gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() && \
+                 !gProp.pSGlobalShell->GetViewOptions()->IsReadonly() && \
+                 !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&\
+                 !gProp.pSGlobalShell->GetViewOptions()->IsWhitespaceHidden() &&\
+                 SwViewOption::IsDocBoundaries())
+//subsidiary lines for sections
+#define IS_SUBS_SECTION (!gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() && \
+                         !gProp.pSGlobalShell->GetViewOptions()->IsReadonly()&&\
+                         !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&\
+                          SwViewOption::IsSectionBoundaries())
+#define IS_SUBS_FLYS (!gProp.pSGlobalShell->GetViewOptions()->IsPagePreview() && \
+                      !gProp.pSGlobalShell->GetViewOptions()->IsReadonly()&&\
+                      !gProp.pSGlobalShell->GetViewOptions()->IsFormView() &&\
+                       SwViewOption::IsObjectBoundaries())
+
+//Class declaration; here because they are only used in this file
+enum class SubColFlags {
+    Page     = 0x01,    //Helplines of the page
+    Tab      = 0x08,   //Helplines inside tables
+    Fly      = 0x10,    //Helplines inside fly frames
+    Sect     = 0x20,    //Helplines inside sections
+};
+namespace o3tl {
+    template<> struct typed_flags<SubColFlags> : is_typed_flags<SubColFlags, 0x39> {};
+}
+
+// Classes collecting the border lines and help lines
+class SwLineRect : public SwRect
+{
+    Color             aColor;
+    SvxBorderLineStyle nStyle;
+    const SwTabFrame *pTab;
+    SubColFlags       nSubColor;  //colorize subsidiary lines
+    bool              bPainted;   //already painted?
+    sal_uInt8         nLock;      //To distinguish the line and the hell layer.
+public:
+    SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyle,
+                const SwTabFrame *pT , const SubColFlags nSCol );
+
+    const Color&         GetColor() const { return aColor;}
+    SvxBorderLineStyle   GetStyle() const { return nStyle; }
+    const SwTabFrame      *GetTab()   const { return pTab;  }
+    void  SetPainted()                    { bPainted = true; }
+    void  Lock( bool bLock )              { if ( bLock )
+                                                ++nLock;
+                                            else if ( nLock )
+                                                --nLock;
+                                          }
+    bool        IsPainted()               const { return bPainted; }
+    bool        IsLocked()                const { return nLock != 0;  }
+    SubColFlags GetSubColor()             const { return nSubColor;}
+
+    bool MakeUnion( const SwRect &rRect, SwPaintProperties const &properties );
+};
+
+#ifdef IOS
+static void dummy_function()
+{
+    pid_t pid = getpid();
+    (void) pid;
+}
+#endif
+
+class SwLineRects
+{
+public:
+    std::vector< SwLineRect > aLineRects;
+    typedef std::vector< SwLineRect >::const_iterator const_iterator;
+    typedef std::vector< SwLineRect >::iterator iterator;
+    typedef std::vector< SwLineRect >::reverse_iterator reverse_iterator;
+    typedef std::vector< SwLineRect >::size_type size_type;
+    size_t nLastCount;  //avoid unnecessary cycles in PaintLines
+    SwLineRects() : nLastCount( 0 )
+    {
+#ifdef IOS
+        // Work around what is either a compiler bug in Xcode 5.1.1,
+        // or some unknown problem in this file. If I ifdef out this
+        // call, I get a crash in SwSubsRects::PaintSubsidiary: the
+        // address of the rLi reference variable is claimed to be
+        // 0x4000000!
+        dummy_function();
+#endif
+    }
+    void AddLineRect( const SwRect& rRect,  const Color *pColor, const SvxBorderLineStyle nStyle,
+                      const SwTabFrame *pTab, const SubColFlags nSCol, SwPaintProperties const &properties );
+    void ConnectEdges( OutputDevice const *pOut, SwPaintProperties const &properties );
+    void PaintLines  ( OutputDevice *pOut, SwPaintProperties const &properties );
+    void LockLines( bool bLock );
+
+    //Limit lines to 100
+    bool isFull() const { return aLineRects.size()>100; }
+};
+
+class SwSubsRects : public SwLineRects
+{
+    void RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects, SwPaintProperties const &properties );
+public:
+    void PaintSubsidiary( OutputDevice *pOut, const SwLineRects *pRects, SwPaintProperties const &properties );
+};
+
+class BorderLines
+{
+    drawinglayer::primitive2d::Primitive2DContainer m_Lines;
+public:
+    void AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine);
+    drawinglayer::primitive2d::Primitive2DContainer GetBorderLines_Clear()
+    {
+        drawinglayer::primitive2d::Primitive2DContainer lines;
+        lines.swap(m_Lines);
+        return lines;
+    }
+};
+
+// Default zoom factor
+const static double aMinDistScale = 0.73;
+const static double aEdgeScale = 0.5;
+
+//To optimize the expensive RetouchColor determination
+Color aGlobalRetoucheColor;
+
+namespace sw
+{
+Color* GetActiveRetoucheColor()
+{
+    return &aGlobalRetoucheColor;
+}
+}
+
+/**
+ * Container for static properties
+ */
+struct SwPaintProperties {
+    // Only repaint the Fly content as well as the background of the Fly content if
+    // a metafile is taken of the Fly.
+    bool                bSFlyMetafile;
+    VclPtr<OutputDevice> pSFlyMetafileOut;
+    SwViewShell        *pSGlobalShell;
+
+    // Retouch for transparent Flys is done by the background of the Flys.
+    // The Fly itself should certainly not be spared out. See PaintBackground and
+    // lcl_SubtractFlys()
+    SwFlyFrame           *pSRetoucheFly;
+    SwFlyFrame           *pSRetoucheFly2;
+    SwFlyFrame           *pSFlyOnlyDraw;
+
+    // The borders will be collected in pSLines during the Paint and later
+    // possibly merge them.
+    // The help lines will be collected and merged in gProp.pSSubsLines. These will
+    // be compared with pSLines before the work in order to avoid help lines
+    // to hide borders.
+    BorderLines        *pBLines;
+    SwLineRects        *pSLines;
+    SwSubsRects        *pSSubsLines;
+
+    // global variable for sub-lines of body, header, footer, section and footnote frames.
+    SwSubsRects        *pSSpecSubsLines;
+    SfxProgress        *pSProgress;
+
+    // Sizes of a pixel and the corresponding halves. Will be reset when
+    // entering SwRootFrame::Paint
+    long                nSPixelSzW;
+    long                nSPixelSzH;
+    long                nSHalfPixelSzW;
+    long                nSHalfPixelSzH;
+    long                nSMinDistPixelW;
+    long                nSMinDistPixelH;
+
+    Color               aSGlobalRetoucheColor;
+
+    // Current zoom factor
+    double              aSScaleX;
+    double              aSScaleY;
+
+    SwPaintProperties()
+      : bSFlyMetafile(false)
+      , pSFlyMetafileOut(nullptr)
+      , pSGlobalShell(nullptr)
+      , pSRetoucheFly(nullptr)
+      , pSRetoucheFly2(nullptr)
+      , pSFlyOnlyDraw(nullptr)
+      , pBLines(nullptr)
+      , pSLines(nullptr)
+      , pSSubsLines(nullptr)
+      , pSSpecSubsLines(nullptr)
+      , pSProgress(nullptr)
+      , nSPixelSzW(0)
+      , nSPixelSzH(0)
+      , nSHalfPixelSzW(0)
+      , nSHalfPixelSzH(0)
+      , nSMinDistPixelW(0)
+      , nSMinDistPixelH(0)
+      , aSScaleX(1)
+      , aSScaleY(1)
+    {
+    }
+
+};
+
+static SwPaintProperties gProp;
+
+namespace {
+
+bool isTableBoundariesEnabled()
+{
+    if (!gProp.pSGlobalShell->GetViewOptions()->IsTable())
+        return false;
+
+    if (gProp.pSGlobalShell->GetViewOptions()->IsPagePreview())
+        return false;
+
+    if (gProp.pSGlobalShell->GetViewOptions()->IsReadonly())
+        return false;
+
+    if (gProp.pSGlobalShell->GetViewOptions()->IsFormView())
+        return false;
+
+    return SwViewOption::IsTableBoundaries();
+}
+
+}
+
+/**
+ * Set borders alignment statics
+ * Adjustment for 'small' twip-to-pixel relations:
+ * For 'small' twip-to-pixel relations (less then 2:1)
+ * values of <gProp.nSHalfPixelSzW> and <gProp.nSHalfPixelSzH> are set to ZERO
+ */
+void SwCalcPixStatics( vcl::RenderContext const *pOut )
+{
+    // determine 'small' twip-to-pixel relation
+    bool bSmallTwipToPxRelW = false;
+    bool bSmallTwipToPxRelH = false;
+    {
+        Size aCheckTwipToPxRelSz( pOut->PixelToLogic( Size( 100, 100 )) );
+        if ( (aCheckTwipToPxRelSz.Width()/100.0) < 2.0 )
+        {
+            bSmallTwipToPxRelW = true;
+        }
+        if ( (aCheckTwipToPxRelSz.Height()/100.0) < 2.0 )
+        {
+            bSmallTwipToPxRelH = true;
+        }
+    }
+
+    Size aSz( pOut->PixelToLogic( Size( 1,1 )) );
+
+    gProp.nSPixelSzW = aSz.Width();
+    if( !gProp.nSPixelSzW )
+        gProp.nSPixelSzW = 1;
+    gProp.nSPixelSzH = aSz.Height();
+    if( !gProp.nSPixelSzH )
+        gProp.nSPixelSzH = 1;
+
+    // consider 'small' twip-to-pixel relations
+    if ( !bSmallTwipToPxRelW )
+    {
+        gProp.nSHalfPixelSzW = gProp.nSPixelSzW / 2 + 1;
+    }
+    else
+    {
+        gProp.nSHalfPixelSzW = 0;
+    }
+    // consider 'small' twip-to-pixel relations
+    if ( !bSmallTwipToPxRelH )
+    {
+        gProp.nSHalfPixelSzH = gProp.nSPixelSzH / 2 + 1;
+    }
+    else
+    {
+        gProp.nSHalfPixelSzH = 0;
+    }
+
+    gProp.nSMinDistPixelW = gProp.nSPixelSzW * 2 + 1;
+    gProp.nSMinDistPixelH = gProp.nSPixelSzH * 2 + 1;
+
+    const MapMode &rMap = pOut->GetMapMode();
+    gProp.aSScaleX = double(rMap.GetScaleX());
+    gProp.aSScaleY = double(rMap.GetScaleY());
+}
+
+/**
+ * To be able to save the statics so the paint is more or less reentrant
+ */
+class SwSavePaintStatics : public SwPaintProperties
+{
+public:
+    SwSavePaintStatics();
+    ~SwSavePaintStatics();
+};
+
+SwSavePaintStatics::SwSavePaintStatics()
+{
+    // Saving globales
+    bSFlyMetafile = gProp.bSFlyMetafile;
+    pSGlobalShell = gProp.pSGlobalShell;
+    pSFlyMetafileOut = gProp.pSFlyMetafileOut;
+    pSRetoucheFly = gProp.pSRetoucheFly;
+    pSRetoucheFly2 = gProp.pSRetoucheFly2;
+    pSFlyOnlyDraw = gProp.pSFlyOnlyDraw;
+    pBLines = gProp.pBLines;
+    pSLines = gProp.pSLines;
+    pSSubsLines = gProp.pSSubsLines;
+    pSSpecSubsLines = gProp.pSSpecSubsLines;
+    pSProgress = gProp.pSProgress;
+    nSPixelSzW = gProp.nSPixelSzW;
+    nSPixelSzH = gProp.nSPixelSzH;
+    nSHalfPixelSzW = gProp.nSHalfPixelSzW;
+    nSHalfPixelSzH = gProp.nSHalfPixelSzH;
+    nSMinDistPixelW = gProp.nSMinDistPixelW;
+    nSMinDistPixelH = gProp.nSMinDistPixelH ;
+    aSGlobalRetoucheColor = aGlobalRetoucheColor;
+    aSScaleX = gProp.aSScaleX;
+    aSScaleY = gProp.aSScaleY;
+
+    // Restoring globales to default
+    gProp.bSFlyMetafile = false;
+    gProp.pSFlyMetafileOut = nullptr;
+    gProp.pSRetoucheFly  = nullptr;
+    gProp.pSRetoucheFly2 = nullptr;
+    gProp.nSPixelSzW = gProp.nSPixelSzH =
+    gProp.nSHalfPixelSzW = gProp.nSHalfPixelSzH =
+    gProp.nSMinDistPixelW = gProp.nSMinDistPixelH = 0;
+    gProp.aSScaleX = gProp.aSScaleY = 1.0;
+    gProp.pBLines = nullptr;
+    gProp.pSLines = nullptr;
+    gProp.pSSubsLines = nullptr;
+    gProp.pSSpecSubsLines = nullptr;
+    gProp.pSProgress = nullptr;
+}
+
+SwSavePaintStatics::~SwSavePaintStatics()
+{
+    // Restoring globales to saved one
+    gProp.pSGlobalShell       = pSGlobalShell;
+    gProp.bSFlyMetafile       = bSFlyMetafile;
+    gProp.pSFlyMetafileOut    = pSFlyMetafileOut;
+    gProp.pSRetoucheFly       = pSRetoucheFly;
+    gProp.pSRetoucheFly2      = pSRetoucheFly2;
+    gProp.pSFlyOnlyDraw       = pSFlyOnlyDraw;
+    gProp.pBLines             = pBLines;
+    gProp.pSLines             = pSLines;
+    gProp.pSSubsLines         = pSSubsLines;
+    gProp.pSSpecSubsLines     = pSSpecSubsLines;
+    gProp.pSProgress          = pSProgress;
+    gProp.nSPixelSzW          = nSPixelSzW;
+    gProp.nSPixelSzH          = nSPixelSzH;
+    gProp.nSHalfPixelSzW      = nSHalfPixelSzW;
+    gProp.nSHalfPixelSzH      = nSHalfPixelSzH;
+    gProp.nSMinDistPixelW     = nSMinDistPixelW;
+    gProp.nSMinDistPixelH     = nSMinDistPixelH;
+    aGlobalRetoucheColor      = aSGlobalRetoucheColor;
+    gProp.aSScaleX            = aSScaleX;
+    gProp.aSScaleY            = aSScaleY;
+}
+
+void BorderLines::AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine)
+{
+    for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend(); ++it)
+    {
+        const drawinglayer::primitive2d::Primitive2DReference aMerged(drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(*it, rLine));
+
+        if (aMerged.is())
+        {
+            *it = aMerged; // replace existing line with merged // lcl_TryMergeBorderLine
+            return;
+        }
+    }
+
+    m_Lines.append(rLine);
+}
+
+SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyl,
+                        const SwTabFrame *pT, const SubColFlags nSCol ) :
+    SwRect( rRect ),
+    nStyle( nStyl ),
+    pTab( pT ),
+    nSubColor( nSCol ),
+    bPainted( false ),
+    nLock( 0 )
+{
+    if ( pCol != nullptr )
+        aColor = *pCol;
+}
+
+bool SwLineRect::MakeUnion( const SwRect &rRect, SwPaintProperties const & properties)
+{
+    // It has already been tested outside, whether the rectangles have
+    // the same orientation (horizontal or vertical), color, etc.
+    if ( Height() > Width() ) //Vertical line
+    {
+        if ( Left()  == rRect.Left() && Width() == rRect.Width() )
+        {
+            // Merge when there is no gap between the lines
+            const long nAdd = properties.nSPixelSzW + properties.nSHalfPixelSzW;
+            if ( Bottom() + nAdd >= rRect.Top() &&
+                 Top()    - nAdd <= rRect.Bottom()  )
+            {
+                Bottom( std::max( Bottom(), rRect.Bottom() ) );
+                Top   ( std::min( Top(),    rRect.Top()    ) );
+                return true;
+            }
+        }
+    }
+    else
+    {
+        if ( Top()  == rRect.Top() && Height() == rRect.Height() )
+        {
+            // Merge when there is no gap between the lines
+            const long nAdd = properties.nSPixelSzW + properties.nSHalfPixelSzW;
+            if ( Right() + nAdd >= rRect.Left() &&
+                 Left()  - nAdd <= rRect.Right() )
+            {
+                Right( std::max( Right(), rRect.Right() ) );
+                Left ( std::min( Left(),  rRect.Left()  ) );
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void SwLineRects::AddLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyle,
+                               const SwTabFrame *pTab, const SubColFlags nSCol, SwPaintProperties const & properties )
+{
+    // Loop backwards because lines which can be combined, can usually be painted
+    // in the same context
+    for (reverse_iterator it = aLineRects.rbegin(); it != aLineRects.rend();
+         ++it)
+    {
+        SwLineRect &rLRect = (*it);
+        // Test for the orientation, color, table
+        if ( rLRect.GetTab() == pTab &&
+             !rLRect.IsPainted() && rLRect.GetSubColor() == nSCol &&
+             (rLRect.Height() > rLRect.Width()) == (rRect.Height() > rRect.Width()) &&
+             (pCol && rLRect.GetColor() == *pCol) )
+        {
+            if ( rLRect.MakeUnion( rRect, properties ) )
+                return;
+        }
+    }
+    aLineRects.emplace_back( rRect, pCol, nStyle, pTab, nSCol );
+}
+
+void SwLineRects::ConnectEdges( OutputDevice const *pOut, SwPaintProperties const & properties )
+{
+    if ( pOut->GetOutDevType() != OUTDEV_PRINTER )
+    {
+        // I'm not doing anything for a too small zoom
+        if ( properties.aSScaleX < aEdgeScale || properties.aSScaleY < aEdgeScale )
+            return;
+    }
+
+    static const long nAdd = 20;
+
+    std::vector<SwLineRect*> aCheck;
+
+    for (size_t i = 0; i < aLineRects.size(); ++i)
+    {
+        SwLineRect &rL1 = aLineRects[i];
+        if ( !rL1.GetTab() || rL1.IsPainted() || rL1.IsLocked() )
+            continue;
+
+        aCheck.clear();
+
+        const bool bVert = rL1.Height() > rL1.Width();
+        long nL1a, nL1b, nL1c, nL1d;
+
+        if ( bVert )
+        {
+            nL1a = rL1.Top();   nL1b = rL1.Left();
+            nL1c = rL1.Right(); nL1d = rL1.Bottom();
+        }
+        else
+        {
+            nL1a = rL1.Left();   nL1b = rL1.Top();
+            nL1c = rL1.Bottom(); nL1d = rL1.Right();
+        }
+
+        // Collect all lines to possibly link with i1
+        for (iterator it2 = aLineRects.begin(); it2 != aLineRects.end(); ++it2)
+        {
+            SwLineRect &rL2 = (*it2);
+            if ( rL2.GetTab() != rL1.GetTab() ||
+                 rL2.IsPainted()              ||
+                 rL2.IsLocked()               ||
+                 (bVert == (rL2.Height() > rL2.Width())) )
+                continue;
+
+            long nL2a, nL2b, nL2c, nL2d;
+            if ( bVert )
+            {
+                nL2a = rL2.Top();   nL2b = rL2.Left();
+                nL2c = rL2.Right(); nL2d = rL2.Bottom();
+            }
+            else
+            {
+                nL2a = rL2.Left();   nL2b = rL2.Top();
+                nL2c = rL2.Bottom(); nL2d = rL2.Right();
+            }
+
+            if ( (nL1a - nAdd < nL2d && nL1d + nAdd > nL2a) &&
+                  ((nL1b >  nL2b && nL1c        < nL2c) ||
+                   (nL1c >= nL2c && nL1b - nAdd < nL2c) ||
+                   (nL1b <= nL2b && nL1c + nAdd > nL2b)) )
+            {
+                aCheck.push_back( &rL2 );
+            }
+        }
+        if ( aCheck.size() < 2 )
+            continue;
+
+        bool bRemove = false;
+
+        // For each line test all following ones.
+        for ( size_t k = 0; !bRemove && k < aCheck.size(); ++k )
+        {
+            SwLineRect &rR1 = *aCheck[k];
+
+            for ( size_t k2 = k+1; !bRemove && k2 < aCheck.size(); ++k2 )
+            {
+                SwLineRect &rR2 = *aCheck[k2];
+                if ( bVert )
+                {
+                    SwLineRect *pLA = nullptr;
+                    SwLineRect *pLB = nullptr;
+                    if ( rR1.Top() < rR2.Top() )
+                    {
+                        pLA = &rR1; pLB = &rR2;
+                    }
+                    else if ( rR1.Top() > rR2.Top() )
+                    {
+                        pLA = &rR2; pLB = &rR1;
+                    }
+                    // are k1 and k2 describing a double line?
+                    if ( pLA && pLA->Bottom() + 60 > pLB->Top() )
+                    {
+                        if ( rL1.Top() < pLA->Top() )
+                        {
+                            if ( rL1.Bottom() == pLA->Bottom() )
+                                continue;    //Small mistake (where?)
+
+                            SwRect aIns( rL1 );
+                            aIns.Bottom( pLA->Bottom() );
+                            if ( !rL1.IsInside( aIns ) )
+                                continue;
+                            aLineRects.emplace_back( aIns, &rL1.GetColor(),
+                                        SvxBorderLineStyle::SOLID,
+                                        rL1.GetTab(), SubColFlags::Tab );
+                            if ( isFull() )
+                            {
+                                --i;
+                                k = aCheck.size();
+                                break;
+                            }
+                        }
+
+                        if ( rL1.Bottom() > pLB->Bottom() )
+                            rL1.Top( pLB->Top() ); // extend i1 on the top
+                        else
+                            bRemove = true; //stopping, remove i1
+                    }
+                }
+                else
+                {
+                    SwLineRect *pLA = nullptr;
+                    SwLineRect *pLB = nullptr;
+                    if ( rR1.Left() < rR2.Left() )
+                    {
+                        pLA = &rR1; pLB = &rR2;
+                    }
+                    else if ( rR1.Left() > rR2.Left() )
+                    {
+                        pLA = &rR2; pLB = &rR1;
+                    }
+                    // Is it double line?
+                    if ( pLA && pLA->Right() + 60 > pLB->Left() )
+                    {
+                        if ( rL1.Left() < pLA->Left() )
+                        {
+                            if ( rL1.Right() == pLA->Right() )
+                                continue;    //small error
+
+                            SwRect aIns( rL1 );
+                            aIns.Right( pLA->Right() );
+                            if ( !rL1.IsInside( aIns ) )
+                                continue;
+                            aLineRects.emplace_back( aIns, &rL1.GetColor(),
+                                        SvxBorderLineStyle::SOLID,
+                                        rL1.GetTab(), SubColFlags::Tab );
+                            if ( isFull() )
+                            {
+                                --i;
+                                k = aCheck.size();
+                                break;
+                            }
+                        }
+                        if ( rL1.Right() > pLB->Right() )
+                            rL1.Left( pLB->Left() );
+                        else
+                            bRemove = true;
+                    }
+                }
+            }
+        }
+        if ( bRemove )
+        {
+            aLineRects.erase(aLineRects.begin() + i);
+            --i;
+        }
+    }
+}
+
+void SwSubsRects::RemoveSuperfluousSubsidiaryLines( const SwLineRects &rRects, SwPaintProperties const & properties )
+{
+    // All help lines that are covered by any border will be removed or split
+    for (size_t i = 0; i < aLineRects.size(); ++i)
+    {
+        // get a copy instead of a reference, because an <insert> may destroy
+        // the object due to a necessary array resize.
+        const SwLineRect aSubsLineRect = SwLineRect(aLineRects[i]);
+
+        // add condition <aSubsLineRect.IsLocked()> in order to consider only
+        // border lines, which are *not* locked.
+        if ( aSubsLineRect.IsPainted() ||
+             aSubsLineRect.IsLocked() )
+            continue;
+
+        const bool bVerticalSubs = aSubsLineRect.Height() > aSubsLineRect.Width();
+        SwRect aSubsRect( aSubsLineRect );
+        if ( bVerticalSubs )
+        {
+            aSubsRect.Left  ( aSubsRect.Left()  - (properties.nSPixelSzW+properties.nSHalfPixelSzW) );
+            aSubsRect.Right ( aSubsRect.Right() + (properties.nSPixelSzW+properties.nSHalfPixelSzW) );
+        }
+        else
+        {
+            aSubsRect.Top   ( aSubsRect.Top()    - (properties.nSPixelSzH+properties.nSHalfPixelSzH) );
+            aSubsRect.Bottom( aSubsRect.Bottom() + (properties.nSPixelSzH+properties.nSHalfPixelSzH) );
+        }
+        for (const_iterator itK = rRects.aLineRects.begin(); itK != rRects.aLineRects.end(); ++itK)
+        {
+            const SwLineRect &rLine = *itK;
+
+            // do *not* consider painted or locked border lines.
+            // #i1837# - locked border lines have to be considered.
+            if ( rLine.IsLocked () )
+                continue;
+
+            if ( !bVerticalSubs == ( rLine.Height() > rLine.Width() ) ) //same direction?
+                continue;
+
+            if ( aSubsRect.IsOver( rLine ) )
+            {
+                if ( bVerticalSubs ) // Vertical?
+                {
+                    if ( aSubsRect.Left()  <= rLine.Right() &&
+                         aSubsRect.Right() >= rLine.Left() )
+                    {
+                        long nTmp = rLine.Top()-(properties.nSPixelSzH+1);
+                        if ( aSubsLineRect.Top() < nTmp )
+                        {
+                            SwRect aNewSubsRect( aSubsLineRect );
+                            aNewSubsRect.Bottom( nTmp );
+                            aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
+                                                aSubsLineRect.GetSubColor() );
+                        }
+                        nTmp = rLine.Bottom()+properties.nSPixelSzH+1;
+                        if ( aSubsLineRect.Bottom() > nTmp )
+                        {
+                            SwRect aNewSubsRect( aSubsLineRect );
+                            aNewSubsRect.Top( nTmp );
+                            aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
+                                                aSubsLineRect.GetSubColor() );
+                        }
+                        aLineRects.erase(aLineRects.begin() + i);
+                        --i;
+                        break;
+                    }
+                }
+                else // Horizontal
+                {
+                    if ( aSubsRect.Top() <= rLine.Bottom() &&
+                         aSubsRect.Bottom() >= rLine.Top() )
+                    {
+                        long nTmp = rLine.Left()-(properties.nSPixelSzW+1);
+                        if ( aSubsLineRect.Left() < nTmp )
+                        {
+                            SwRect aNewSubsRect( aSubsLineRect );
+                            aNewSubsRect.Right( nTmp );
+                            aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
+                                                aSubsLineRect.GetSubColor() );
+                        }
+                        nTmp = rLine.Right()+properties.nSPixelSzW+1;
+                        if ( aSubsLineRect.Right() > nTmp )
+                        {
+                            SwRect aNewSubsRect( aSubsLineRect );
+                            aNewSubsRect.Left( nTmp );
+                            aLineRects.emplace_back( aNewSubsRect, nullptr, aSubsLineRect.GetStyle(), nullptr,
+                                                aSubsLineRect.GetSubColor() );
+                        }
+                        aLineRects.erase(aLineRects.begin() + i);
+                        --i;
+                        break;
+                    }
+                }
+            }
+        }
+    }
+}
+
+void SwLineRects::LockLines( bool bLock )
+{
+    for (iterator it = aLineRects.begin(); it != aLineRects.end(); ++it)
+       (*it).Lock( bLock );
+}
+
+static void lcl_DrawDashedRect( OutputDevice * pOut, SwLineRect const & rLRect )
+{
+    long startX = rLRect.Left(  ), endX;
+    long startY = rLRect.Top(  ),  endY;
+
+    // Discriminate vertically stretched rect from horizontally stretched
+    // and restrict minimum nHalfLWidth to 1
+    long nHalfLWidth = std::max( static_cast<long>(std::min( rLRect.Width(  ), rLRect.Height(  ) ) / 2), 1L );
+
+    if ( rLRect.Height(  ) > rLRect.Width(  ) )
+    {
+        startX += nHalfLWidth;
+        endX = startX;
+        endY = startY + rLRect.Height(  );
+    }
+    else
+    {
+        startY += nHalfLWidth;
+        endY = startY;
+        endX = startX + rLRect.Width(  );
+    }
+
+    svtools::DrawLine( *pOut, Point( startX, startY ), Point( endX, endY ),
+            sal_uInt32( nHalfLWidth * 2 ), rLRect.GetStyle( ) );
+}
+
+void SwLineRects::PaintLines( OutputDevice *pOut, SwPaintProperties const &properties )
+{
+    // Paint the borders. Sadly two passes are needed.
+    // Once for the inside and once for the outside edges of tables
+    if ( aLineRects.size() != nLastCount )
+    {
+        // #i16816# tagged pdf support
+        SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
+
+        pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
+        pOut->SetFillColor();
+        pOut->SetLineColor();
+        ConnectEdges( pOut, properties );
+        const Color *pLast = nullptr;
+
+        bool bPaint2nd = false;
+        size_t nMinCount = aLineRects.size();
+
+        for ( size_t i = 0; i < aLineRects.size(); ++i )
+        {
+            SwLineRect &rLRect = aLineRects[i];
+
+            if ( rLRect.IsPainted() )
+                continue;
+
+            if ( rLRect.IsLocked() )
+            {
+                nMinCount = std::min( nMinCount, i );
+                continue;
+            }
+
+            // Paint it now or in the second pass?
+            bool bPaint = true;
+            if ( rLRect.GetTab() )
+            {
+                if ( rLRect.Height() > rLRect.Width() )
+                {
+                    // Vertical edge, overlapping with the table edge?
+                    SwTwips nLLeft  = rLRect.Left()  - 30,
+                            nLRight = rLRect.Right() + 30,
+                            nTLeft  = rLRect.GetTab()->Frame().Left() + rLRect.GetTab()->Prt().Left(),
+                            nTRight = rLRect.GetTab()->Frame().Left() + rLRect.GetTab()->Prt().Right();
+                    if ( (nTLeft >= nLLeft && nTLeft <= nLRight) ||
+                         (nTRight>= nLLeft && nTRight<= nLRight) )
+                        bPaint = false;
+                }
+                else
+                {
+                    // Horizontal edge, overlapping with the table edge?
+                    SwTwips nLTop    = rLRect.Top()    - 30,
+                            nLBottom = rLRect.Bottom() + 30,
+                            nTTop    = rLRect.GetTab()->Frame().Top()  + rLRect.GetTab()->Prt().Top(),
+                            nTBottom = rLRect.GetTab()->Frame().Top()  + rLRect.GetTab()->Prt().Bottom();
+                    if ( (nTTop    >= nLTop && nTTop      <= nLBottom) ||
+                         (nTBottom >= nLTop && nTBottom <= nLBottom) )
+                        bPaint = false;
+                }
+            }
+            if ( bPaint )
+            {
+                if ( !pLast || *pLast != rLRect.GetColor() )
+                {
+                    pLast = &rLRect.GetColor();
+
+                    DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
+                    if( properties.pSGlobalShell->GetWin() &&
+                        Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+                        pOut->SetDrawMode( DrawModeFlags::Default );
+
+                    pOut->SetLineColor( *pLast );
+                    pOut->SetFillColor( *pLast );
+                    pOut->SetDrawMode( nOldDrawMode );
+                }
+
+                if( !rLRect.IsEmpty() )
+                    lcl_DrawDashedRect( pOut, rLRect );
+                rLRect.SetPainted();
+            }
+            else
+                bPaint2nd = true;
+        }
+        if ( bPaint2nd )
+        {
+            for ( size_t i = 0; i < aLineRects.size(); ++i )
+            {
+                SwLineRect &rLRect = aLineRects[i];
+                if ( rLRect.IsPainted() )
+                    continue;
+
+                if ( rLRect.IsLocked() )
+                {
+                    nMinCount = std::min( nMinCount, i );
+                    continue;
+                }
+
+                if ( !pLast || *pLast != rLRect.GetColor() )
+                {
+                    pLast = &rLRect.GetColor();
+
+                    DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
+                    if( properties.pSGlobalShell->GetWin() &&
+                        Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+                    {
+                        pOut->SetDrawMode( DrawModeFlags::Default );
+                    }
+
+                    pOut->SetFillColor( *pLast );
+                    pOut->SetDrawMode( nOldDrawMode );
+                }
+                if( !rLRect.IsEmpty() )
+                    lcl_DrawDashedRect( pOut, rLRect );
+                rLRect.SetPainted();
+            }
+        }
+        nLastCount = nMinCount;
+        pOut->Pop();
+    }
+}
+
+void SwSubsRects::PaintSubsidiary( OutputDevice *pOut,
+                                   const SwLineRects *pRects,
+                                   SwPaintProperties const & properties )
+{
+    if ( !aLineRects.empty() )
+    {
+        // #i16816# tagged pdf support
+        SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, *pOut );
+
+        // Remove all help line that are almost covered (tables)
+        for (size_type i = 0; i != aLineRects.size(); ++i)
+        {
+            SwLineRect &rLi = aLineRects[i];
+            const bool bVerticalSubs = rLi.Height() > rLi.Width();
+
+            for (size_type k = i + 1; k != aLineRects.size(); ++k)
+            {
+                SwLineRect &rLk = aLineRects[k];
+                if ( rLi.SSize() == rLk.SSize() )
+                {
+                    if ( bVerticalSubs == ( rLk.Height() > rLk.Width() ) )
+                    {
+                        if ( bVerticalSubs )
+                        {
+                            long nLi = rLi.Right();
+                            long nLk = rLk.Right();
+                            if ( rLi.Top() == rLk.Top() &&
+                                 ((nLi < rLk.Left() && nLi+21 > rLk.Left()) ||
+                                  (nLk < rLi.Left() && nLk+21 > rLi.Left())))
+                            {
+                                aLineRects.erase(aLineRects.begin() + k);
+                                // don't continue with inner loop any more:
+                                // the array may shrink!
+                                --i;
+                                break;
+                            }
+                        }
+                        else
+                        {
+                            long nLi = rLi.Bottom();
+                            long nLk = rLk.Bottom();
+                            if ( rLi.Left() == rLk.Left() &&
+                                 ((nLi < rLk.Top() && nLi+21 > rLk.Top()) ||
+                                  (nLk < rLi.Top() && nLk+21 > rLi.Top())))
+                            {
+                                aLineRects.erase(aLineRects.begin() + k);
+                                // don't continue with inner loop any more:
+                                // the array may shrink!
+                                --i;
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        if ( pRects && (!pRects->aLineRects.empty()) )
+            RemoveSuperfluousSubsidiaryLines( *pRects, properties );
+
+        if ( !aLineRects.empty() )
+        {
+            pOut->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
+            pOut->SetLineColor();
+
+            // Reset draw mode in high contrast mode in order to get fill color
+            // set at output device. Recover draw mode after draw of lines.
+            // Necessary for the subsidiary lines painted by the fly frames.
+            DrawModeFlags nOldDrawMode = pOut->GetDrawMode();
+            if( gProp.pSGlobalShell->GetWin() &&
+                Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+            {
+                pOut->SetDrawMode( DrawModeFlags::Default );
+            }
+
+            for (SwSubsRects::iterator it = aLineRects.begin(); it != aLineRects.end();
+                 ++it)
+            {
+                SwLineRect &rLRect = (*it);
+                // Add condition <!rLRect.IsLocked()> to prevent paint of locked subsidiary lines.
+                if ( !rLRect.IsPainted() &&
+                     !rLRect.IsLocked() )
+                {
+                    const Color *pCol = nullptr;
+                    switch ( rLRect.GetSubColor() )
+                    {
+                        case SubColFlags::Page: pCol = &SwViewOption::GetDocBoundariesColor(); break;
+                        case SubColFlags::Fly: pCol = &SwViewOption::GetObjectBoundariesColor(); break;
+                        case SubColFlags::Tab: pCol = &SwViewOption::GetTableBoundariesColor(); break;
+                        case SubColFlags::Sect: pCol = &SwViewOption::GetSectionBoundColor(); break;
+                    }
+
+                    if (pCol && pOut->GetFillColor() != *pCol)
+                        pOut->SetFillColor( *pCol );
+                    pOut->DrawRect( rLRect.SVRect() );
+
+                    rLRect.SetPainted();
+                }
+            }
+
+            pOut->SetDrawMode( nOldDrawMode );
+
+            pOut->Pop();
+        }
+    }
+}
+
+// Various functions that are use in this file.
+
+/**
+ * Function <SwAlignRect(..)> is also used outside this file
+ *
+ * Correction: adjust rectangle on pixel level in order to make sure,
+ * that the border "leaves its original pixel", if it has to
+ * No prior adjustments for odd relation between pixel and twip
+ */
+void SwAlignRect( SwRect &rRect, const SwViewShell *pSh, const vcl::RenderContext* pRenderContext )
+{
+    if( !rRect.HasArea() )
+        return;
+
+    // Make sure that view shell (parameter <pSh>) exists, if the output device
+    // is taken from this view shell --> no output device, no alignment
+    // Output device taken from view shell <pSh>, if <gProp.bSFlyMetafile> not set
+    if ( !gProp.bSFlyMetafile && !pSh )
+    {
+        return;
+    }
+
+    const vcl::RenderContext *pOut = gProp.bSFlyMetafile ?
+                        gProp.pSFlyMetafileOut.get() : pRenderContext;
+
+    // Hold original rectangle in pixel
+    const tools::Rectangle aOrgPxRect = pOut->LogicToPixel( rRect.SVRect() );
+    // Determine pixel-center rectangle in twip
+    const SwRect aPxCenterRect( pOut->PixelToLogic( aOrgPxRect ) );
+
+    // Perform adjustments on pixel level.
+    SwRect aAlignedPxRect( aOrgPxRect );
+    if ( rRect.Top() > aPxCenterRect.Top() )
+    {
+        // 'leave pixel overlapping on top'
+        aAlignedPxRect.Top( aAlignedPxRect.Top() + 1 );
+    }
+
+    if ( rRect.Bottom() < aPxCenterRect.Bottom() )
+    {
+        // 'leave pixel overlapping on bottom'
+        aAlignedPxRect.Bottom( aAlignedPxRect.Bottom() - 1 );
+    }
+
+    if ( rRect.Left() > aPxCenterRect.Left() )
+    {
+        // 'leave pixel overlapping on left'
+        aAlignedPxRect.Left( aAlignedPxRect.Left() + 1 );
+    }
+
+    if ( rRect.Right() < aPxCenterRect.Right() )
+    {
+        // 'leave pixel overlapping on right'
+        aAlignedPxRect.Right( aAlignedPxRect.Right() - 1 );
+    }
+
+    // Consider negative width/height check, if aligned SwRect has negative width/height.
+    // If Yes, adjust it to width/height = 0 twip.
+    // NOTE: A SwRect with negative width/height can occur, if the width/height
+    //     of the given SwRect in twip was less than a pixel in twip and that
+    //     the alignment calculates that the aligned SwRect should not contain
+    //     the pixels the width/height is on.
+    if ( aAlignedPxRect.Width() < 0 )
+    {
+        aAlignedPxRect.Width(0);
+    }
+    if ( aAlignedPxRect.Height() < 0 )
+    {
+        aAlignedPxRect.Height(0);
+    }
+    // Consider zero width/height for converting a rectangle from
+    // pixel to logic it needs a width/height. Thus, set width/height
+    // to one, if it's zero and correct this on the twip level after the conversion.
+    bool bZeroWidth = false;
+    if ( aAlignedPxRect.Width() == 0 )
+    {
+        aAlignedPxRect.Width(1);
+        bZeroWidth = true;
+    }
+    bool bZeroHeight = false;
+    if ( aAlignedPxRect.Height() == 0 )
+    {
+        aAlignedPxRect.Height(1);
+        bZeroHeight = true;
+    }
+
+    rRect = pOut->PixelToLogic( aAlignedPxRect.SVRect() );
+
+    // Consider zero width/height and adjust calculated aligned twip rectangle.
+    // Reset width/height to zero; previous negative width/height haven't to be considered.
+    if ( bZeroWidth )
+    {
+        rRect.Width(0);
+    }
+    if ( bZeroHeight )
+    {
+        rRect.Height(0);
+    }
+}
+
+/**
+ * Helper for twip adjustments on pixel base
+ *
+ * This method compares the x- or y-pixel position of two twip-points.
+ * If the x-/y-pixel positions are the same, the x-/y-pixel position of
+ * the second twip point is adjusted by a given amount of pixels
+*/
+static void lcl_CompPxPosAndAdjustPos( const vcl::RenderContext&  _rOut,
+                                const Point&         _rRefPt,
+                                Point&               _rCompPt,
+                                const bool          _bChkXPos,
+                                const sal_Int8       _nPxAdjustment )
+{
+    const Point aRefPxPt = _rOut.LogicToPixel( _rRefPt );
+    Point aCompPxPt = _rOut.LogicToPixel( _rCompPt );
+
+    if ( _bChkXPos )
+    {
+        if ( aCompPxPt.X() == aRefPxPt.X() )
+        {
+            aCompPxPt.X() += _nPxAdjustment ;
+            const Point aAdjustedCompPt = _rOut.PixelToLogic( aCompPxPt );
+            _rCompPt.X() = aAdjustedCompPt.X();
+        }
+    }
+    else
+    {
+        if ( aCompPxPt.Y() == aRefPxPt.Y() )
+        {
+            aCompPxPt.Y() += _nPxAdjustment ;
+            const Point aAdjustedCompPt = _rOut.PixelToLogic( aCompPxPt );
+            _rCompPt.Y() = aAdjustedCompPt.Y();
+        }
+    }
+}
+
+/**
+ * Method to pixel-align rectangle for drawing graphic object
+ *
+ * Because we are drawing graphics from the left-top-corner in conjunction
+ * with size coordinates, these coordinates have to be calculated at a pixel
+ * level.
+ * Thus, we convert the rectangle to pixel and then convert to left-top-corner
+ * and then get size of pixel rectangle back to logic.
+ * This calculation is necessary, because there's a different between
+ * the conversion from logic to pixel of a normal rectangle with its left-top-
+ * and right-bottom-corner and the same conversion of the same rectangle
+ * with left-top-corner and size.
+ *
+ * NOTE: Call this method before each <GraphicObject.Draw(...)>
+*/
+void SwAlignGrfRect( SwRect *pGrfRect, const vcl::RenderContext &rOut )
+{
+    tools::Rectangle aPxRect = rOut.LogicToPixel( pGrfRect->SVRect() );
+    pGrfRect->Pos( rOut.PixelToLogic( aPxRect.TopLeft() ) );
+    pGrfRect->SSize( rOut.PixelToLogic( aPxRect.GetSize() ) );
+}
+
+static long lcl_AlignWidth( const long nWidth, SwPaintProperties const & properties )
+{
+    if ( nWidth )
+    {
+        const long nW = nWidth % properties.nSPixelSzW;
+
+        if ( !nW || nW > properties.nSHalfPixelSzW )
+            return std::max(1L, nWidth - properties.nSHalfPixelSzW);
+    }
+    return nWidth;
+}
+
+static long lcl_AlignHeight( const long nHeight, SwPaintProperties const & properties )
+{
+    if ( nHeight )
+    {
+        const long nH = nHeight % properties.nSPixelSzH;
+
+        if ( !nH || nH > properties.nSHalfPixelSzH )
+            return std::max(1L, nHeight - properties.nSHalfPixelSzH);
+    }
+    return nHeight;
+}
+
+static long lcl_MinHeightDist( const long nDist, SwPaintProperties const & properties )
+{
+    if ( properties.aSScaleX < aMinDistScale || properties.aSScaleY < aMinDistScale )
+        return nDist;
+    return ::lcl_AlignHeight( std::max( nDist, properties.nSMinDistPixelH ), properties);
+}
+
+/**
+ * Calculate PrtArea plus surrounding plus shadow
+ */
+static void lcl_CalcBorderRect( SwRect &rRect, const SwFrame *pFrame,
+                                        const SwBorderAttrs &rAttrs,
+                                        const bool bShadow,
+                                        SwPaintProperties const & properties)
+{
+    // Special handling for cell frames.
+    // The printing area of a cell frame is completely enclosed in the frame area
+    // and a cell frame has no shadow. Thus, for cell frames the calculated
+    // area equals the frame area.
+    // Notes: Borders of cell frames in R2L text direction will switch its side
+    //        - left border is painted on the right; right border on the left.
+    //        See <lcl_PaintLeftLine> and <lcl_PaintRightLine>.
+    if( pFrame->IsSctFrame() )
+    {
+        rRect = pFrame->Prt();
+        rRect.Pos() += pFrame->Frame().Pos();
+    }
+    else if ( pFrame->IsCellFrame() )
+        rRect = pFrame->Frame();
+    else
+    {
+        rRect = pFrame->Prt();
+        rRect.Pos() += pFrame->Frame().Pos();
+
+        if ( rAttrs.IsLine() || rAttrs.IsBorderDist() ||
+             (bShadow && rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE) )
+        {
+            SwRectFn fnRect = pFrame->IsVertical() ? ( pFrame->IsVertLR() ? fnRectVertL2R : fnRectVert ) : fnRectHori;
+
+            const SvxBoxItem &rBox = rAttrs.GetBox();
+            const bool bTop = 0 != (pFrame->*fnRect->fnGetTopMargin)();
+            if ( bTop )
+            {
+                SwTwips nDiff = rBox.GetTop() ?
+                    rBox.CalcLineSpace( SvxBoxItemLine::TOP ) :
+                    ( rAttrs.IsBorderDist() ?
+                      // Increase of distance by one twip is incorrect.
+                      rBox.GetDistance( SvxBoxItemLine::TOP ) : 0 );
+                if( nDiff )
+                    (rRect.*fnRect->fnSubTop)( nDiff );
+            }
+
+            const bool bBottom = 0 != (pFrame->*fnRect->fnGetBottomMargin)();
+            if ( bBottom )
+            {
+                SwTwips nDiff = 0;
+                // #i29550#
+                if ( pFrame->IsTabFrame() &&
+                     static_cast<const SwTabFrame*>(pFrame)->IsCollapsingBorders() )
+                {
+                    // For collapsing borders, we have to add the height of
+                    // the height of the last line
+                    nDiff = static_cast<const SwTabFrame*>(pFrame)->GetBottomLineSize();
+                }
+                else
+                {
+                    nDiff = rBox.GetBottom() ?
+                    rBox.CalcLineSpace( SvxBoxItemLine::BOTTOM ) :
+                    ( rAttrs.IsBorderDist() ?
+                      // Increase of distance by one twip is incorrect.
+                      rBox.GetDistance( SvxBoxItemLine::BOTTOM ) : 0 );
+                }
+                if( nDiff )
+                    (rRect.*fnRect->fnAddBottom)( nDiff );
+            }
+
+            if ( rBox.GetLeft() )
+                (rRect.*fnRect->fnSubLeft)( rBox.CalcLineSpace( SvxBoxItemLine::LEFT ) );
+            else if ( rAttrs.IsBorderDist() )
+                 // Increase of distance by one twip is incorrect.
+                (rRect.*fnRect->fnSubLeft)( rBox.GetDistance( SvxBoxItemLine::LEFT ) );
+
+            if ( rBox.GetRight() )
+                (rRect.*fnRect->fnAddRight)( rBox.CalcLineSpace( SvxBoxItemLine::RIGHT ) );
+            else if ( rAttrs.IsBorderDist() )
+                 // Increase of distance by one twip is incorrect.
+                (rRect.*fnRect->fnAddRight)( rBox.GetDistance( SvxBoxItemLine::RIGHT ) );
+
+            if ( bShadow && rAttrs.GetShadow().GetLocation() != SvxShadowLocation::NONE )
+            {
+                const SvxShadowItem &rShadow = rAttrs.GetShadow();
+                if ( bTop )
+                    (rRect.*fnRect->fnSubTop)(rShadow.CalcShadowSpace(SvxShadowItemSide::TOP));
+                (rRect.*fnRect->fnSubLeft)(rShadow.CalcShadowSpace(SvxShadowItemSide::LEFT));
+                if ( bBottom )
+                    (rRect.*fnRect->fnAddBottom)
+                                    (rShadow.CalcShadowSpace( SvxShadowItemSide::BOTTOM ));
+                (rRect.*fnRect->fnAddRight)(rShadow.CalcShadowSpace(SvxShadowItemSide::RIGHT));
+            }
+        }
+    }
+
+    ::SwAlignRect( rRect, properties.pSGlobalShell, properties.pSGlobalShell ? properties.pSGlobalShell->GetOut() : nullptr );
+}
+
+/**
+ * Extend left/right border/shadow rectangle to bottom of previous frame/to
+ * top of next frame, if border/shadow is joined with previous/next frame
+ */
+static void lcl_ExtendLeftAndRight( SwRect&                _rRect,
+                                         const SwFrame&           _rFrame,
+                                         const SwBorderAttrs&   _rAttrs,
+                                         const SwRectFn&        _rRectFn )
+{
+    if ( _rAttrs.JoinedWithPrev( _rFrame ) )
+    {
+        const SwFrame* pPrevFrame = _rFrame.GetPrev();
+        (_rRect.*_rRectFn->fnSetTop)( (pPrevFrame->*_rRectFn->fnGetPrtBottom)() );
+    }
+    if ( _rAttrs.JoinedWithNext( _rFrame ) )
+    {
+        const SwFrame* pNextFrame = _rFrame.GetNext();
+        (_rRect.*_rRectFn->fnSetBottom)( (pNextFrame->*_rRectFn->fnGetPrtTop)() );
+    }
+}
+
+/// Returns a range suitable for subtraction when lcl_SubtractFlys() is used.
+/// Otherwise DrawFillAttributes() expands the clip path itself.
+static basegfx::B2DRange lcl_ShrinkFly(const SwRect& rRect)
+{
+    static MapMode aMapMode(MapUnit::MapTwip);
+    static const Size aSingleUnit = Application::GetDefaultDevice()->PixelToLogic(Size(1, 1), aMapMode);
+
+    double x1 = rRect.Left() + aSingleUnit.getWidth();
+    double y1 = rRect.Top() + aSingleUnit.getHeight();
+    double x2 = rRect.Right() - aSingleUnit.getWidth();
+    double y2 = rRect.Bottom() - aSingleUnit.getHeight();
+
+    return basegfx::B2DRange(x1, y1, x2, y2);
+}
+
+static void lcl_SubtractFlys( const SwFrame *pFrame, const SwPageFrame *pPage,
+   const SwRect &rRect, SwRegionRects &rRegion, basegfx::tools::B2DClipState& rClipState, SwPaintProperties const & rProperties)
+{
+    const SwSortedObjs& rObjs = *pPage->GetSortedObjs();
+    const SwFlyFrame* pSelfFly = pFrame->IsInFly() ? pFrame->FindFlyFrame() : gProp.pSRetoucheFly2;
+    if (!gProp.pSRetoucheFly)
+        gProp.pSRetoucheFly = gProp.pSRetoucheFly2;
+
+    for (size_t j = 0; (j < rObjs.size()) && !rRegion.empty(); ++j)
+    {
+        const SwAnchoredObject* pAnchoredObj = rObjs[j];
+        const SdrObject* pSdrObj = pAnchoredObj->GetDrawObj();
+
+        // Do not consider invisible objects
+        if (!pPage->GetFormat()->GetDoc()->getIDocumentDrawModelAccess().IsVisibleLayerId(pSdrObj->GetLayer()))
+            continue;
+
+        if (dynamic_cast< const SwFlyFrame *>( pAnchoredObj ) ==  nullptr)
+            continue;
+
+        const SwFlyFrame *pFly = static_cast<const SwFlyFrame*>(pAnchoredObj);
+
+        if (pSelfFly == pFly || gProp.pSRetoucheFly == pFly || !rRect.IsOver(pFly->Frame()))
+            continue;
+
+        if (!pFly->GetFormat()->GetPrint().GetValue() &&
+                (OUTDEV_PRINTER == gProp.pSGlobalShell->GetOut()->GetOutDevType() ||
+                gProp.pSGlobalShell->IsPreview()))
+            continue;
+
+        const bool bLowerOfSelf = pSelfFly && pFly->IsLowerOf( pSelfFly );
+
+        //For character bound Flys only examine those Flys in which it is not
+        //anchored itself.
+        //Why only for character bound ones you may ask? It never makes sense to
+        //subtract frames in which it is anchored itself right?
+        if (pSelfFly && pSelfFly->IsLowerOf(pFly))
+            continue;
+
+        //Any why does it not apply for the RetoucheFly too?
+        if (gProp.pSRetoucheFly && gProp.pSRetoucheFly->IsLowerOf(pFly))
+            continue;
+
+#if OSL_DEBUG_LEVEL > 0
+        //Flys who are anchored inside their own one, must have a bigger OrdNum
+        //or be character bound.
+        if (pSelfFly && bLowerOfSelf)
+        {
+            OSL_ENSURE( pFly->IsFlyInContentFrame() ||
+                    pSdrObj->GetOrdNumDirect() > pSelfFly->GetVirtDrawObj()->GetOrdNumDirect(),
+                    "Fly with wrong z-Order" );
+        }
+#endif
+
+        bool bStopOnHell = true;
+        if (pSelfFly)
+        {
+            const SdrObject *pTmp = pSelfFly->GetVirtDrawObj();
+            if (pSdrObj->GetLayer() == pTmp->GetLayer())
+            {
+                if (pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect())
+                    //In the same layer we only observe those that are above.
+                    continue;
+            }
+            else
+            {
+                if (!bLowerOfSelf && !pFly->GetFormat()->GetOpaque().GetValue())
+                    //From other layers we are only interested in non
+                    //transparent ones or those that are internal
+                    continue;
+                bStopOnHell = false;
+            }
+        }
+        if (gProp.pSRetoucheFly)
+        {
+            const SdrObject *pTmp = gProp.pSRetoucheFly->GetVirtDrawObj();
+            if ( pSdrObj->GetLayer() == pTmp->GetLayer() )
+            {
+                if ( pSdrObj->GetOrdNumDirect() < pTmp->GetOrdNumDirect() )
+                    //In the same layer we only observe those that are above.
+                    continue;
+            }
+            else
+            {
+                if (!pFly->IsLowerOf( gProp.pSRetoucheFly ) && !pFly->GetFormat()->GetOpaque().GetValue())
+                    //From other layers we are only interested in non
+                    //transparent ones or those that are internal
+                    continue;
+                bStopOnHell = false;
+            }
+        }
+
+        //If the content of the Fly is transparent, we subtract it only if it's
+        //contained in the hell layer.
+        const IDocumentDrawModelAccess& rIDDMA = pFly->GetFormat()->getIDocumentDrawModelAccess();
+        bool bHell = pSdrObj->GetLayer() == rIDDMA.GetHellId();
+        if ( (bStopOnHell && bHell) ||
+             /// Change internal order of condition
+             ///    first check "!bHell", then "..->Lower()" and "..->IsNoTextFrame()"
+             ///    have not to be performed, if frame is in "Hell"
+             ( !bHell && pFly->Lower() && pFly->Lower()->IsNoTextFrame() &&
+               (static_cast<SwNoTextFrame const*>(pFly->Lower())->IsTransparent() ||
+                static_cast<SwNoTextFrame const*>(pFly->Lower())->HasAnimation() ||
+                 pFly->GetFormat()->GetSurround().IsContour()
+               )
+             )
+           )
+            continue;
+
+        // Own if-statements for transparent background/shadow of fly frames
+        // in order to handle special conditions.
+        if (pFly->IsBackgroundTransparent())
+        {
+            // Background <pFly> is transparent drawn. Thus normally, its region
+            // have not to be subtracted from given region.
+            // But, if method is called for a fly frame and
+            // <pFly> is a direct lower of this fly frame and
+            // <pFly> inherites its transparent background brush from its parent,
+            // then <pFly> frame area have to be subtracted from given region.
+            // NOTE: Because in Status Quo transparent backgrounds can only be
+            //     assigned to fly frames, the handle of this special case
+            //     avoids drawing of transparent areas more than once, if
+            //     a fly frame inherites a transparent background from its
+            //     parent fly frame.
+            if (pFrame->IsFlyFrame() &&
+                (pFly->GetAnchorFrame()->FindFlyFrame() == pFrame) &&
+                pFly->GetFormat()->IsBackgroundBrushInherited()
+               )
+            {
+                SwRect aRect;
+                SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
+                const SwBorderAttrs &rAttrs = *aAccess.Get();
+                ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
+                rRegion -= aRect;
+                rClipState.subtractRange(lcl_ShrinkFly(aRect));
+                continue;
+            }
+            else
+            {
+                continue;
+            }
+        }
+
+        if (bHell && pFly->GetAnchorFrame()->IsInFly())
+        {
+            //So the border won't get dismantled by the background of the other
+            //Fly.
+            SwRect aRect;
+            SwBorderAttrAccess aAccess( SwFrame::GetCache(), static_cast<SwFrame const *>(pFly) );
+            const SwBorderAttrs &rAttrs = *aAccess.Get();
+            ::lcl_CalcBorderRect( aRect, pFly, rAttrs, true, rProperties );
+            rRegion -= aRect;
+            rClipState.subtractRange(lcl_ShrinkFly(aRect));
+        }
+        else
+        {
+            SwRect aRect( pFly->Prt() );
+            aRect += pFly->Frame().Pos();
+            rRegion -= aRect;
+            rClipState.subtractRange(lcl_ShrinkFly(aRect));
+        }
+    }
+    if (gProp.pSRetoucheFly == gProp.pSRetoucheFly2)
+        gProp.pSRetoucheFly = nullptr;
+}
+
+static void lcl_implDrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
+                                 vcl::RenderContext* _pOut,
+                                 const SwRect& _rAlignedPaintRect,
+                                 const GraphicObject& _rGraphicObj,
+                                 SwPaintProperties const & properties)
+{
+    /// determine color of background
+    ///     If color of background brush is not "no fill"/"auto fill" or
+    ///     <SwPaintProperties.bSFlyMetafile> is set, use color of background brush, otherwise
+    ///     use global retouche color.
+    const Color aColor( ( (_rBackgrdBrush.GetColor() != COL_TRANSPARENT) || properties.bSFlyMetafile )
+                        ? _rBackgrdBrush.GetColor()
+                        : aGlobalRetoucheColor );
+
+    /// determine, if background color have to be drawn transparent
+    /// and calculate transparency percent value
+    sal_Int8 nTransparencyPercent = 0;
+    bool bDrawTransparent = false;
+    if ( aColor.GetTransparency() != 0 )
+    ///     background color is transparent --> draw transparent.
+    {
+        bDrawTransparent = true;
+        nTransparencyPercent = (aColor.GetTransparency()*100 + 0x7F)/0xFF;
+    }
+    else if ( (_rGraphicObj.GetAttr().GetTransparency() != 0) &&
+                (_rBackgrdBrush.GetColor() == COL_TRANSPARENT) )
+    ///     graphic is drawn transparent and background color is
+    ///     "no fill"/"auto fill" --> draw transparent
+    {
+        bDrawTransparent = true;
+        nTransparencyPercent = (_rGraphicObj.GetAttr().GetTransparency()*100 + 0x7F)/0xFF;
+    }
+
+    if ( bDrawTransparent )
+    {
+        /// draw background transparent
+        if( _pOut->GetFillColor() != aColor.GetRGBColor() )
+            _pOut->SetFillColor( aColor.GetRGBColor() );
+        tools::PolyPolygon aPoly( _rAlignedPaintRect.SVRect() );
+        _pOut->DrawTransparent( aPoly, nTransparencyPercent );
+    }
+    else
+    {
+        /// draw background opaque
+        if ( _pOut->GetFillColor() != aColor )
+            _pOut->SetFillColor( aColor );
+        _pOut->DrawRect( _rAlignedPaintRect.SVRect() );
+    }
+}
+
+/**
+ * This is a local help method to draw a background for a graphic
+ *
+ * Under certain circumstances we have to draw a background for a graphic.
+ * This method takes care of the conditions and draws the background with the
+ * corresponding color.
+ * Method introduced for bug fix #103876# in order to optimize drawing tiled
+ * background graphics. Previously, this code was integrated in method
+ * <lcl_DrawGraphic>.
+ * Method implemented as a inline, checking the conditions and calling method
+ * method <lcl_implDrawGraphicBackgrd(..)> for the intrinsic drawing.
+ *
+ * @param _rBackgrdBrush
+ * background brush contain the color the background has to be drawn.
+ *
+ * @param _pOut
+ * output device the background has to be drawn in.
+ *
+ * @param _rAlignedPaintRect
+ * paint rectangle in the output device, which has to be drawn with the background.
+ * rectangle have to be aligned by method ::SwAlignRect
+ *
+ * @param _rGraphicObj
+ * graphic object, for which the background has to be drawn. Used for checking
+ * the transparency of its bitmap, its type and if the graphic is drawn transparent
+ *
+ * @param _bNumberingGraphic
+ * boolean indicating that graphic is used as a numbering.
+ *
+ * @param _bBackgrdAlreadyDrawn
+ * boolean (optional; default: false) indicating, if the background is already drawn.
+*/
+static inline void lcl_DrawGraphicBackgrd( const SvxBrushItem& _rBackgrdBrush,
+                                    OutputDevice* _pOut,
+                                    const SwRect& _rAlignedPaintRect,
+                                    const GraphicObject& _rGraphicObj,
+                                    bool _bNumberingGraphic,
+                                    SwPaintProperties const & properties,
+                                    bool _bBackgrdAlreadyDrawn = false)
+{
+    // draw background with background color, if
+    //     (1) graphic is not used as a numbering AND
+    //     (2) background is not already drawn AND
+    //     (3) intrinsic graphic is transparent OR intrinsic graphic doesn't exists
+    if ( !_bNumberingGraphic &&
+         !_bBackgrdAlreadyDrawn &&
+         ( _rGraphicObj.IsTransparent() || _rGraphicObj.GetType() == GraphicType::NONE  )
+       )
+    {
+        lcl_implDrawGraphicBackgrd( _rBackgrdBrush, _pOut, _rAlignedPaintRect, _rGraphicObj, properties );
+    }
+}
+
+/**
+ * NNOTE: the transparency of the background graphic is saved in
+ * SvxBrushItem.GetGraphicObject(<shell>).GetAttr().Set/GetTransparency()
+ * and is considered in the drawing of the graphic
+ *
+ * Thus, to provide transparent background graphic for text frames nothing
+ * has to be coded
+ *
+ * Use align rectangle for drawing graphic Pixel-align coordinates for
+ * drawing graphic
+ * Outsource code for drawing background of the graphic
+ * with a background color in method <lcl_DrawGraphicBackgrd>
+ *
+ * Also, change type of <bGrfNum> and <bClip> from <bool> to <bool>
+ */
+static void lcl_DrawGraphic( const SvxBrushItem& rBrush, vcl::RenderContext *pOut,
+                      SwViewShell &rSh, const SwRect &rGrf, const SwRect &rOut,
+                      bool bClip, bool bGrfNum,
+                      SwPaintProperties const & properties,
+                      bool bBackgrdAlreadyDrawn )
+                      // add parameter <bBackgrdAlreadyDrawn> to indicate
+                      // that the background is already drawn.
+{
+    // Calculate align rectangle from parameter <rGrf> and use aligned
+    // rectangle <aAlignedGrfRect> in the following code
+    SwRect aAlignedGrfRect = rGrf;
+    ::SwAlignRect( aAlignedGrfRect, &rSh, pOut );
+
+    // Change type from <bool> to <bool>.
+    const bool bNotInside = bClip && !rOut.IsInside( aAlignedGrfRect );
+    if ( bNotInside )
+    {
+        pOut->Push( PushFlags::CLIPREGION );
+        pOut->IntersectClipRegion( rOut.SVRect() );
+    }
+
+    GraphicObject *pGrf = const_cast<GraphicObject*>(rBrush.GetGraphicObject());
+
+    // Outsource drawing of background with a background color
+    ::lcl_DrawGraphicBackgrd( rBrush, pOut, aAlignedGrfRect, *pGrf, bGrfNum, properties, bBackgrdAlreadyDrawn );
+
+    // Because for drawing a graphic left-top-corner and size coordinates are
+    // used, these coordinates have to be determined on pixel level.
+    ::SwAlignGrfRect( &aAlignedGrfRect, *pOut );
+
+    paintGraphicUsingPrimitivesHelper(*pOut,
+        *pGrf, pGrf->GetAttr(), aAlignedGrfRect);
+
+    if ( bNotInside )
+        pOut->Pop();
+}
+
+bool DrawFillAttributes(
+    const drawinglayer::attribute::SdrAllFillAttributesHelperPtr& rFillAttributes,
+    const SwRect& rOriginalLayoutRect,
+    const SwRegionRects& rPaintRegion,

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list