[Libreoffice-commits] core.git: Branch 'feature/RotGrfFlyFrame' - sw/source sw/uiconfig

Armin Le Grand Armin.Le.Grand at cib.de
Tue Oct 3 15:03:01 UTC 2017


 sw/source/core/layout/paintfrm.cxx.orig          | 7565 +++++++++++++++++++++++
 sw/uiconfig/swriter/toolbar/graphicobjectbar.xml |    2 
 sw/uiconfig/swxform/toolbar/graphicobjectbar.xml |    4 
 3 files changed, 7568 insertions(+), 3 deletions(-)

New commits:
commit e1742c565420bfb82b486e46fe0f55515ac2001b
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/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,
+    const basegfx::tools::B2DClipState& rClipState,
+    vcl::RenderContext& rOut)
+{
+    if(rFillAttributes.get() && rFillAttributes->isUsed())
+    {
+        basegfx::B2DRange aPaintRange(
+            rPaintRegion.GetOrigin().Left(),
+            rPaintRegion.GetOrigin().Top(),
+            rPaintRegion.GetOrigin().Right(),
+            rPaintRegion.GetOrigin().Bottom());
+
+        if (!aPaintRange.isEmpty() &&
+            !rPaintRegion.empty() &&
+            !basegfx::fTools::equalZero(aPaintRange.getWidth()) &&
+            !basegfx::fTools::equalZero(aPaintRange.getHeight()))
+        {
+            const SvtOptionsDrawinglayer aSvtOptionsDrawinglayer;
+
+            // need to expand for correct AAed and non-AAed visualization as primitive.
+            // This must probably be removed again when we will be able to get all Writer visualization
+            // as primitives and Writer prepares all it's stuff in high precision coordinates (also
+            // needs to avoid moving boundaries around to better show overlapping stuff...)
+            if(aSvtOptionsDrawinglayer.IsAntiAliasing())
+            {
+                // if AAed in principle expand by 0.5 in all directions. Since painting edges of
+                // AAed regions does not add to no transparence (0.5 opacity covered by 0.5 opacity
+                // is not full opacity but 0.75 opacity) we need some overlap here to avoid paint
+                // artifacts. Checked experimentally - a little bit more in Y is needed, probably
+                // due to still existing integer alignment and crunching in writer.
+                static double fExpandX = 0.55;
+                static double fExpandY = 0.70;
+                const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(fExpandX, fExpandY));
+
+                aPaintRange.expand(aPaintRange.getMinimum() - aSingleUnit);
+                aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
+            }
+            else
+            {
+                // if not AAed expand by one unit to bottom right due to the missing unit
+                // from SwRect/Rectangle integer handling
+                const basegfx::B2DVector aSingleUnit(rOut.GetInverseViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+
+                aPaintRange.expand(aPaintRange.getMaximum() + aSingleUnit);
+            }
+
+            const basegfx::B2DRange aDefineRange(
+                rOriginalLayoutRect.Left(),
+                rOriginalLayoutRect.Top(),
+                rOriginalLayoutRect.Right(),
+                rOriginalLayoutRect.Bottom());
+
+            const drawinglayer::primitive2d::Primitive2DContainer& rSequence = rFillAttributes->getPrimitive2DSequence(
+                aPaintRange,
+                aDefineRange);
+
+            if(rSequence.size())
+            {
+                drawinglayer::primitive2d::Primitive2DContainer const*
+                    pPrimitives(&rSequence);
+                drawinglayer::primitive2d::Primitive2DContainer primitives;
+                // tdf#86578 the awful lcl_SubtractFlys hack
+                if (rPaintRegion.size() > 1 || rPaintRegion[0] != rPaintRegion.GetOrigin())
+                {
+                    basegfx::B2DPolyPolygon const maskRegion(rClipState.getClipPoly());
+                    primitives.resize(1);
+                    primitives[0] = new drawinglayer::primitive2d::MaskPrimitive2D(
+                            maskRegion, rSequence);
+                    pPrimitives = &primitives;
+                }
+                assert(pPrimitives && pPrimitives->size());
+
+                const drawinglayer::geometry::ViewInformation2D aViewInformation2D(
+                    basegfx::B2DHomMatrix(),
+                    rOut.GetViewTransformation(),
+                    aPaintRange,
+                    nullptr,
+                    0.0,
+                    uno::Sequence< beans::PropertyValue >());
+                drawinglayer::processor2d::BaseProcessor2D* pProcessor = drawinglayer::processor2d::createProcessor2DFromOutputDevice(
+                    rOut,
+                    aViewInformation2D);
+
+                if(pProcessor)
+                {
+                    pProcessor->process(*pPrimitives);
+
+                    delete pProcessor;
+
+                    return true;
+                }
+            }
+        }
+    }
+
+    return false;
+}
+
+void DrawGraphic(
+    const SvxBrushItem *pBrush,
+    vcl::RenderContext *pOutDev,
+    const SwRect &rOrg,
+    const SwRect &rOut,
+    const sal_uInt8 nGrfNum,
+    const bool bConsiderBackgroundTransparency )
+    // Add 6th parameter to indicate that method should
+    // consider background transparency, saved in the color of the brush item
+{
+    SwViewShell &rSh = *gProp.pSGlobalShell;
+    bool bReplaceGrfNum = GRFNUM_REPLACE == nGrfNum;
+    bool bGrfNum = GRFNUM_NO != nGrfNum;
+    Size aGrfSize;
+    SvxGraphicPosition ePos = GPOS_NONE;
+    if( pBrush && !bReplaceGrfNum )
+    {
+        if( rSh.GetViewOptions()->IsGraphic() )
+        {
+            OUString referer;
+            SfxObjectShell * sh = rSh.GetDoc()->GetPersist();
+            if (sh != nullptr && sh->HasName()) {
+                referer = sh->GetMedium()->GetName();
+            }
+            const Graphic* pGrf = pBrush->GetGraphic(referer);
+            if( pGrf && GraphicType::NONE != pGrf->GetType() )
+            {
+                ePos = pBrush->GetGraphicPos();
+                if( pGrf->IsSupportedGraphic() )
+                    // don't the use the specific output device! Bug 94802
+                    aGrfSize = ::GetGraphicSizeTwip( *pGrf, nullptr );
+            }
+        }
+        else
+            bReplaceGrfNum = bGrfNum;
+    }
+
+    SwRect aGrf;
+    aGrf.SSize( aGrfSize );
+    bool bDraw = true;
+    bool bRetouche = true;
+    switch ( ePos )
+    {
+    case GPOS_LT:
+        aGrf.Pos() = rOrg.Pos();
+        break;
+
+    case GPOS_MT:
+        aGrf.Pos().Y() = rOrg.Top();
+        aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2;
+        break;
+
+    case GPOS_RT:
+        aGrf.Pos().Y() = rOrg.Top();
+        aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width();
+        break;
+
+    case GPOS_LM:
+        aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2;
+        aGrf.Pos().X() = rOrg.Left();
+        break;
+
+    case GPOS_MM:
+        aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2;
+        aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2;
+        break;
+
+    case GPOS_RM:
+        aGrf.Pos().Y() = rOrg.Top() + rOrg.Height()/2 - aGrfSize.Height()/2;
+        aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width();
+        break;
+
+    case GPOS_LB:
+        aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height();
+        aGrf.Pos().X() = rOrg.Left();
+        break;
+
+    case GPOS_MB:
+        aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height();
+        aGrf.Pos().X() = rOrg.Left() + rOrg.Width()/2 - aGrfSize.Width()/2;
+        break;
+
+    case GPOS_RB:
+        aGrf.Pos().Y() = rOrg.Bottom() - aGrfSize.Height();
+        aGrf.Pos().X() = rOrg.Right() - aGrfSize.Width();
+        break;
+
+    case GPOS_AREA:
+        aGrf = rOrg;
+        // Despite the fact that the background graphic has to fill the complete
+        // area, we already checked, whether the graphic will completely fill out
+        // the region the <rOut> that is to be painted. Thus, nothing has to be
+        // touched again.
+        // E.g. this is the case for a Fly Frame without a background
+        // brush positioned on the border of the page which inherited the background
+        // brush from the page.
+        bRetouche = !rOut.IsInside( aGrf );
+        break;
+
+    case GPOS_TILED:
+        {
+            // draw background of tiled graphic before drawing tiled graphic in loop
+            // determine graphic object
+            GraphicObject* pGraphicObj = const_cast< GraphicObject* >(pBrush->GetGraphicObject());
+            // calculate aligned paint rectangle
+            SwRect aAlignedPaintRect = rOut;
+            ::SwAlignRect( aAlignedPaintRect, &rSh, pOutDev );
+            // draw background color for aligned paint rectangle
+            lcl_DrawGraphicBackgrd( *pBrush, pOutDev, aAlignedPaintRect, *pGraphicObj, bGrfNum, gProp );
+
+            // set left-top-corner of background graphic to left-top-corner of the
+            // area, from which the background brush is determined.
+            aGrf.Pos() = rOrg.Pos();
+            // setup clipping at output device
+            pOutDev->Push( PushFlags::CLIPREGION );
+            pOutDev->IntersectClipRegion( rOut.SVRect() );
+            // use new method <GraphicObject::DrawTiled(::)>
+            {
+                // calculate paint offset
+                Point aPaintOffset( aAlignedPaintRect.Pos() - aGrf.Pos() );
+                // draw background graphic tiled for aligned paint rectangle
+                // #i42643#
+                // For PDF export, every draw operation for bitmaps takes a
+                // noticeable amount of place (~50 characters). Thus, optimize
+                // between tile bitmap size and number of drawing operations here.
+
+                //                  A_out
+                // n_chars = k1 *  ---------- + k2 * A_bitmap
+                //                  A_bitmap
+
+                // minimum n_chars is obtained for (derive for  A_bitmap,
+                // set to 0, take positive solution):
+                //                   k1
+                // A_bitmap = Sqrt( ---- A_out )
+                //                   k2
+
+                // where k1 is the number of chars per draw operation, and
+                // k2 is the number of chars per bitmap pixel.
+                // This is approximately 50 and 7 for current PDF writer, respectively.
+
+                const double    k1( 50 );
+                const double    k2( 7 );
+                const Size      aSize( aAlignedPaintRect.SSize() );
+                const double    Abitmap( k1/k2 * static_cast<double>(aSize.Width())*aSize.Height() );
+
+                pGraphicObj->DrawTiled( pOutDev,
+                                        aAlignedPaintRect.SVRect(),
+                                        aGrf.SSize(),
+                                        Size( aPaintOffset.X(), aPaintOffset.Y() ),
+                                        GraphicManagerDrawFlags::STANDARD,
+                                        std::max( 128, static_cast<int>( sqrt(sqrt( Abitmap)) + .5 ) ) );
+            }
+            // reset clipping at output device
+            pOutDev->Pop();
+            // set <bDraw> and <bRetouche> to false, indicating that background
+            // graphic and background are already drawn.
+            bDraw = bRetouche = false;
+        }
+        break;
+
+    case GPOS_NONE:
+        bDraw = false;
+        break;
+
+    default: OSL_ENSURE( !pOutDev, "new Graphic position?" );
+    }
+
+    /// init variable <bGrfBackgrdAlreadDrawn> to indicate, if background of
+    /// graphic is already drawn or not.
+    bool bGrfBackgrdAlreadyDrawn = false;
+    if ( bRetouche )
+    {
+        pOutDev->Push( PushFlags::FILLCOLOR|PushFlags::LINECOLOR );
+        pOutDev->SetLineColor();
+
+        // check, if a existing background graphic (not filling the complete
+        // background) is transparent drawn and the background color is
+        // "no fill" respectively "auto fill", if background transparency
+        // has to be considered.
+        // If YES, memorize transparency of background graphic.
+        // check also, if background graphic bitmap is transparent.
+        bool bTransparentGrfWithNoFillBackgrd = false;
+        sal_Int32 nGrfTransparency = 0;
+        bool bGrfIsTransparent = false;
+        if ( (ePos != GPOS_NONE) &&
+             (ePos != GPOS_TILED) && (ePos != GPOS_AREA)
+           )
+        {
+            GraphicObject *pGrf = const_cast<GraphicObject*>(pBrush->GetGraphicObject());
+            if ( bConsiderBackgroundTransparency )
+            {
+                GraphicAttr aGrfAttr = pGrf->GetAttr();
+                if ( (aGrfAttr.GetTransparency() != 0) &&
+                     (pBrush->GetColor() == COL_TRANSPARENT)
+                   )
+                {
+                    bTransparentGrfWithNoFillBackgrd = true;
+                    nGrfTransparency = aGrfAttr.GetTransparency();
+                }
+            }
+            if ( pGrf->IsTransparent() )
+            {
+                bGrfIsTransparent = true;
+            }
+        }
+
+        // to get color of brush, check background color against COL_TRANSPARENT ("no fill"/"auto fill")
+        // instead of checking, if transparency is not set.
+        const Color aColor( pBrush &&
+                            ( !(pBrush->GetColor() == COL_TRANSPARENT) ||
+                              gProp.bSFlyMetafile )
+                    ? pBrush->GetColor()
+                    : aGlobalRetoucheColor );
+
+        // determine, if background region have to be
+        //     drawn transparent.
+        //     background region has to be drawn transparent, if
+        //         background transparency have to be considered
+        //     AND
+        //       ( background color is transparent OR
+        //         background graphic is transparent and background color is "no fill"
+        //       )
+
+        enum DrawStyle {
+            Default,
+            Transparent,
+        } eDrawStyle = Default;
+
+        if (bConsiderBackgroundTransparency &&
+                ( ( aColor.GetTransparency() != 0) ||
+                bTransparentGrfWithNoFillBackgrd ) )
+        {
+            eDrawStyle = Transparent;
+        }
+
+        // #i75614# reset draw mode in high contrast mode in order to get fill color set
+        const DrawModeFlags nOldDrawMode = pOutDev->GetDrawMode();
+        if ( gProp.pSGlobalShell->GetWin() &&
+             Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+        {
+            pOutDev->SetDrawMode( DrawModeFlags::Default );
+        }
+
+        // OD 06.08.2002 #99657# - if background region has to be drawn
+        // transparent, set only the RGB values of the background color as
+        // the fill color for the output device.
+        switch (eDrawStyle)
+        {
+            case Transparent:
+            {
+                if( pOutDev->GetFillColor() != aColor.GetRGBColor() )
+                    pOutDev->SetFillColor( aColor.GetRGBColor() );
+                break;
+            }
+            default:
+            {
+                if( pOutDev->GetFillColor() != aColor )
+                    pOutDev->SetFillColor( aColor );
+                break;
+            }
+        }
+
+        // #i75614#
+        // restore draw mode
+        pOutDev->SetDrawMode( nOldDrawMode );
+
+        // OD 02.09.2002 #99657#
+        switch (eDrawStyle)
+        {
+            case Transparent:
+            {
+                // background region have to be drawn transparent.
+                // Thus, create a poly-polygon from the region and draw it with
+                // the corresponding transparency percent.
+                tools::PolyPolygon aDrawPoly( rOut.SVRect() );
+                if ( aGrf.HasArea() )
+                {
+                    if ( !bGrfIsTransparent )
+                    {
+                        // subtract area of background graphic from draw area
+                        // OD 08.10.2002 #103898# - consider only that part of the
+                        // graphic area that is overlapping with draw area.
+                        SwRect aTmpGrf = aGrf;
+                        aTmpGrf.Intersection( rOut );
+                        if ( aTmpGrf.HasArea() )
+                        {
+                            tools::Polygon aGrfPoly( aTmpGrf.SVRect() );
+                            aDrawPoly.Insert( aGrfPoly );
+                        }
+                    }
+                    else
+                        bGrfBackgrdAlreadyDrawn = true;
+                }
+                // calculate transparency percent:
+                // ( <transparency value[0x01..0xFF]>*100 + 0x7F ) / 0xFF
+                // If there is a background graphic with a background color "no fill"/"auto fill",
+                // the transparency value is taken from the background graphic,
+                // otherwise take the transparency value from the color.
+                sal_Int8 nTransparencyPercent = static_cast<sal_Int8>(
+                  (( bTransparentGrfWithNoFillBackgrd ? nGrfTransparency : aColor.GetTransparency()
+                   )*100 + 0x7F)/0xFF);
+                // draw poly-polygon transparent
+                pOutDev->DrawTransparent( aDrawPoly, nTransparencyPercent );
+
+                break;
+            }
+            case Default:
+            default:
+            {
+                SwRegionRects aRegion( rOut, 4 );
+                if ( !bGrfIsTransparent )
+                    aRegion -= aGrf;
+                else
+                    bGrfBackgrdAlreadyDrawn = true;
+                // loop rectangles of background region, which has to be drawn
+                for( size_t i = 0; i < aRegion.size(); ++i )
+                {
+                    pOutDev->DrawRect( aRegion[i].SVRect() );
+                }
+            }
+        }
+        pOutDev ->Pop();
+    }
+
+    if( bDraw && aGrf.IsOver( rOut ) )
+        // OD 02.09.2002 #99657#
+        // add parameter <bGrfBackgrdAlreadyDrawn>
+        lcl_DrawGraphic( *pBrush, pOutDev, rSh, aGrf, rOut, true, bGrfNum, gProp,
+                         bGrfBackgrdAlreadyDrawn );
+
+    if( bReplaceGrfNum )
+    {
+        const BitmapEx& rBmp = rSh.GetReplacementBitmap(false);
+        vcl::Font aTmp( pOutDev->GetFont() );
+        Graphic::DrawEx( pOutDev, aEmptyOUStr, aTmp, rBmp, rOrg.Pos(), rOrg.SSize() );
+    }
+}
+
+/**
+ * Local helper for SwRootFrame::Paint(..) - Adjust given rectangle to pixel size
+ *
+ * By OD at 27.09.2002 for #103636#
+ * In order to avoid paint errors caused by multiple alignments (e.g. ::SwAlignRect(..))
+ * and other changes to the to be painted rectangle, this method is called for the
+ * rectangle to be painted in order to adjust it to the pixel it is overlapping
+*/
+static void lcl_AdjustRectToPixelSize( SwRect& io_aSwRect, const vcl::RenderContext &aOut )
+{
+    // local constant object of class <Size> to determine number of Twips
+    // representing a pixel.
+    const Size aTwipToPxSize( aOut.PixelToLogic( Size( 1,1 )) );
+
+    // local object of class <Rectangle> in Twip coordinates
+    // calculated from given rectangle aligned to pixel centers.
+    const tools::Rectangle aPxCenterRect = aOut.PixelToLogic(
+            aOut.LogicToPixel( io_aSwRect.SVRect() ) );
+
+    // local constant object of class <Rectangle> representing given rectangle
+    // in pixel.
+    const tools::Rectangle aOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
+
+    // calculate adjusted rectangle from pixel centered rectangle.
+    // Due to rounding differences <aPxCenterRect> doesn't exactly represents
+    // the Twip-centers. Thus, adjust borders by half of pixel width/height plus 1.
+    // Afterwards, adjust calculated Twip-positions of the all borders.
+    tools::Rectangle aSizedRect = aPxCenterRect;
+    aSizedRect.Left() -= (aTwipToPxSize.Width()/2 + 1);
+    aSizedRect.Right() += (aTwipToPxSize.Width()/2 + 1);
+    aSizedRect.Top() -= (aTwipToPxSize.Height()/2 + 1);
+    aSizedRect.Bottom() += (aTwipToPxSize.Height()/2 + 1);
+
+    // adjust left()
+    while ( (aOut.LogicToPixel(aSizedRect)).Left() < aOrgPxRect.Left() )
+    {
+        ++aSizedRect.Left();
+    }
+    // adjust right()
+    while ( (aOut.LogicToPixel(aSizedRect)).Right() > aOrgPxRect.Right() )
+    {
+        --aSizedRect.Right();
+    }
+    // adjust top()
+    while ( (aOut.LogicToPixel(aSizedRect)).Top() < aOrgPxRect.Top() )
+    {
+        ++aSizedRect.Top();
+    }
+    // adjust bottom()
+    while ( (aOut.LogicToPixel(aSizedRect)).Bottom() > aOrgPxRect.Bottom() )
+    {
+        --aSizedRect.Bottom();
+    }
+
+    io_aSwRect = SwRect( aSizedRect );
+
+#if OSL_DEBUG_LEVEL > 0
+    tools::Rectangle aTestOrgPxRect = aOut.LogicToPixel( io_aSwRect.SVRect() );
+    tools::Rectangle aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+    OSL_ENSURE( aTestOrgPxRect == aTestNewPxRect,
+            "Error in lcl_AlignRectToPixelSize(..): Adjusted rectangle has incorrect position or size");
+    // check Left()
+    --aSizedRect.Left();
+    aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+    OSL_ENSURE( aTestOrgPxRect.Left() >= (aTestNewPxRect.Left()+1),
+            "Error in lcl_AlignRectToPixelSize(..): Left() not correct adjusted");
+    ++aSizedRect.Left();
+    // check Right()
+    ++aSizedRect.Right();
+    aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+    OSL_ENSURE( aTestOrgPxRect.Right() <= (aTestNewPxRect.Right()-1),
+            "Error in lcl_AlignRectToPixelSize(..): Right() not correct adjusted");
+    --aSizedRect.Right();
+    // check Top()
+    --aSizedRect.Top();
+    aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+    OSL_ENSURE( aTestOrgPxRect.Top() >= (aTestNewPxRect.Top()+1),
+            "Error in lcl_AlignRectToPixelSize(..): Top() not correct adjusted");
+    ++aSizedRect.Top();
+    // check Bottom()
+    ++aSizedRect.Bottom();
+    aTestNewPxRect = aOut.LogicToPixel( aSizedRect );
+    OSL_ENSURE( aTestOrgPxRect.Bottom() <= (aTestNewPxRect.Bottom()-1),
+            "Error in lcl_AlignRectToPixelSize(..): Bottom() not correct adjusted");
+    --aSizedRect.Bottom();
+#endif
+}
+
+// FUNCTIONS USED FOR COLLAPSING TABLE BORDER LINES START
+
+struct SwLineEntry
+{
+    SwTwips mnKey;
+    SwTwips mnStartPos;
+    SwTwips mnEndPos;
+
+    svx::frame::Style maAttribute;
+
+    enum OverlapType { NO_OVERLAP, OVERLAP1, OVERLAP2, OVERLAP3 };
+
+public:
+    SwLineEntry( SwTwips nKey,
+                 SwTwips nStartPos,
+                 SwTwips nEndPos,
+                 const svx::frame::Style& rAttribute );
+
+    OverlapType Overlaps( const SwLineEntry& rComp ) const;
+};
+
+SwLineEntry::SwLineEntry( SwTwips nKey,
+                          SwTwips nStartPos,
+                          SwTwips nEndPos,
+                          const svx::frame::Style& rAttribute )
+    :   mnKey( nKey ),
+        mnStartPos( nStartPos ),
+        mnEndPos( nEndPos ),
+        maAttribute( rAttribute )
+{
+}
+
+/*
+
+ 1. ----------    rOld
+       ---------- rNew
+
+ 2. ----------    rOld
+    ------------- rNew
+
+ 3.    -------    rOld
+    ------------- rNew
+
+ 4. ------------- rOld
+       ---------- rNew
+
+ 5. ----------    rOld
+       ----       rNew
+
+ 6. ----------    rOld
+    ----------    rNew
+
+ 7. ------------- rOld
+    ----------    rNew
+
+ 8.    ---------- rOld
+    ------------- rNew
+
+ 9.    ---------- rOld
+    ----------    rNew
+*/
+
+SwLineEntry::OverlapType SwLineEntry::Overlaps( const SwLineEntry& rNew )  const
+{
+    SwLineEntry::OverlapType eRet = OVERLAP3;
+
+    if ( mnStartPos >= rNew.mnEndPos || mnEndPos <= rNew.mnStartPos )
+        eRet = NO_OVERLAP;
+
+    // 1, 2, 3
+    else if ( mnEndPos < rNew.mnEndPos )
+        eRet = OVERLAP1;
+
+    // 4, 5, 6, 7
+    else if ( mnStartPos <= rNew.mnStartPos && mnEndPos >= rNew.mnEndPos )
+        eRet = OVERLAP2;
+
+    // 8, 9
+    return eRet;
+}
+
+struct lt_SwLineEntry
+{
+    bool operator()( const SwLineEntry& e1, const SwLineEntry& e2 ) const
+    {
+        return e1.mnStartPos < e2.mnStartPos;
+    }
+};
+
+typedef std::set< SwLineEntry, lt_SwLineEntry > SwLineEntrySet;
+typedef std::map< SwTwips, SwLineEntrySet > SwLineEntryMap;
+
+class SwTabFramePainter
+{
+    SwLineEntryMap maVertLines;
+    SwLineEntryMap maHoriLines;
+    const SwTabFrame& mrTabFrame;
+
+    void Insert( SwLineEntry&, bool bHori );
+    void Insert( const SwFrame& rFrame, const SvxBoxItem& rBoxItem );
+    void HandleFrame( const SwLayoutFrame& rFrame );
+    void FindStylesForLine( const Point&,
+                            const Point&,
+                            svx::frame::Style*,
+                            bool bHori ) const;
+
+public:
+    explicit SwTabFramePainter( const SwTabFrame& rTabFrame );
+
+    void PaintLines( OutputDevice& rDev, const SwRect& rRect ) const;
+};
+
+SwTabFramePainter::SwTabFramePainter( const SwTabFrame& rTabFrame )
+    : mrTabFrame( rTabFrame )
+{
+    HandleFrame( rTabFrame );
+}
+
+void SwTabFramePainter::HandleFrame( const SwLayoutFrame& rLayoutFrame )
+{
+    // Add border lines of cell frames. Skip covered cells. Skip cells
+    // in special row span row, which do not have a negative row span:
+    if ( rLayoutFrame.IsCellFrame() && !rLayoutFrame.IsCoveredCell() )
+    {
+        const SwCellFrame* pThisCell = static_cast<const SwCellFrame*>(&rLayoutFrame);
+        const SwRowFrame* pRowFrame = static_cast<const SwRowFrame*>(pThisCell->GetUpper());
+        const long nRowSpan = pThisCell->GetTabBox()->getRowSpan();
+        if ( !pRowFrame->IsRowSpanLine() || nRowSpan > 1 || nRowSpan < -1 )
+        {
+            SwBorderAttrAccess aAccess( SwFrame::GetCache(), &rLayoutFrame );
+            const SwBorderAttrs& rAttrs = *aAccess.Get();
+            const SvxBoxItem& rBox = rAttrs.GetBox();
+            Insert( rLayoutFrame, rBox );
+        }
+    }
+
+    // Recurse into lower layout frames, but do not recurse into lower tabframes.
+    const SwFrame* pLower = rLayoutFrame.Lower();
+    while ( pLower )
+    {
+        const SwLayoutFrame* pLowerLayFrame = dynamic_cast<const SwLayoutFrame*>(pLower);
+        if ( pLowerLayFrame && !pLowerLayFrame->IsTabFrame() )
+            HandleFrame( *pLowerLayFrame );
+
+        pLower = pLower->GetNext();
+    }
+}
+
+void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) const
+{
+    // #i16816# tagged pdf support
+    SwTaggedPDFHelper aTaggedPDFHelper( nullptr, nullptr, nullptr, rDev );
+
+    SwLineEntryMap::const_iterator aIter = maHoriLines.begin();
+    bool bHori = true;
+
+    // color for subsidiary lines:
+    const Color& rCol( SwViewOption::GetTableBoundariesColor() );
+
+    // high contrast mode:
+    // overrides the color of non-subsidiary lines.
+    const Color* pHCColor = nullptr;
+    DrawModeFlags nOldDrawMode = rDev.GetDrawMode();
+    if( gProp.pSGlobalShell->GetWin() &&
+        Application::GetSettings().GetStyleSettings().GetHighContrastMode() )
+    {
+        pHCColor = &SwViewOption::GetFontColor();
+        rDev.SetDrawMode( DrawModeFlags::Default );
+    }
+
+    const SwFrame* pUpper = mrTabFrame.GetUpper();
+    SwRect aUpper( pUpper->Prt() );
+    aUpper.Pos() += pUpper->Frame().Pos();
+    SwRect aUpperAligned( aUpper );
+    ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev );
+    drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence;
+    drawinglayer::primitive2d::Primitive2DContainer aVerticalSequence;
+
+    while ( true )
+    {
+        if ( bHori && aIter == maHoriLines.end() )
+        {
+            aIter = maVertLines.begin();
+            bHori = false;
+        }
+
+        if ( !bHori && aIter == maVertLines.end() )
+            break;
+
+        const SwLineEntrySet& rEntrySet = (*aIter).second;
+        for (SwLineEntrySet::const_iterator aSetIter = rEntrySet.begin();
+                 aSetIter != rEntrySet.end(); ++aSetIter)
+        {
+            const SwLineEntry& rEntry = *aSetIter;
+            const svx::frame::Style& rEntryStyle( (*aSetIter).maAttribute );
+
+            Point aStart, aEnd;
+            if ( bHori )
+            {
+                aStart.X() = rEntry.mnStartPos;
+                aStart.Y() = rEntry.mnKey;
+                aEnd.X() = rEntry.mnEndPos;
+                aEnd.Y() = rEntry.mnKey;
+            }
+            else
+            {
+                aStart.X() = rEntry.mnKey;
+                aStart.Y() = rEntry.mnStartPos;
+                aEnd.X() = rEntry.mnKey;
+                aEnd.Y() = rEntry.mnEndPos;
+            }
+
+            svx::frame::Style aStyles[ 7 ];
+            aStyles[ 0 ] = rEntryStyle;
+            FindStylesForLine( aStart, aEnd, aStyles, bHori );
+            SwRect aRepaintRect( aStart, aEnd );
+
+            // the repaint rectangle has to be moved a bit for the centered lines:
+            SwTwips nRepaintRectSize = !rEntryStyle.GetWidth() ? 1 : rEntryStyle.GetWidth();
+            if ( bHori )
+            {
+                aRepaintRect.Height( 2 * nRepaintRectSize );
+                aRepaintRect.Pos().Y() -= nRepaintRectSize;
+            }
+            else
+            {
+                aRepaintRect.Width( 2 * nRepaintRectSize );
+                aRepaintRect.Pos().X() -= nRepaintRectSize;
+            }
+
+            if (!rRect.IsOver(aRepaintRect))
+            {
+                continue;
+            }
+
+            // subsidiary lines
+            const Color* pTmpColor = nullptr;
+            if (0 == aStyles[ 0 ].GetWidth())
+            {
+                if (isTableBoundariesEnabled() && gProp.pSGlobalShell->GetWin())
+                    aStyles[ 0 ].Set( rCol, rCol, rCol, false, 1, 0, 0 );
+                else
+                    aStyles[0].SetType(SvxBorderLineStyle::NONE);
+            }
+            else
+                pTmpColor = pHCColor;
+
+            // The (twip) positions will be adjusted to meet these requirements:
+            // 1. The y coordinates are located in the middle of the pixel grid
+            // 2. The x coordinated are located at the beginning of the pixel grid
+            // This is done, because the horizontal lines are painted "at
+            // beginning", whereas the vertical lines are painted "centered".
+            // By making the line sizes a multiple of one pixel size, we can
+            // assure that all lines having the same twip size have the same
+            // pixel size, independent of their position on the screen.
+            Point aPaintStart = rDev.PixelToLogic( rDev.LogicToPixel(aStart) );
+            Point aPaintEnd = rDev.PixelToLogic( rDev.LogicToPixel(aEnd) );
+
+            if (gProp.pSGlobalShell->GetWin())
+            {
+                // The table borders do not use SwAlignRect, but all the other frames do.
+                // Therefore we tweak the outer borders a bit to achieve that the outer
+                // borders match the subsidiary lines of the upper:
+                if (aStart.X() == aUpper.Left())
+                    aPaintStart.X() = aUpperAligned.Left();
+                else if (aStart.X() == aUpper.Rigth_())
+                    aPaintStart.X() = aUpperAligned.Rigth_();
+                if (aStart.Y() == aUpper.Top())
+                    aPaintStart.Y() = aUpperAligned.Top();
+                else if (aStart.Y() == aUpper.Bottom_())
+                    aPaintStart.Y() = aUpperAligned.Bottom_();
+
+                if (aEnd.X() == aUpper.Left())
+                    aPaintEnd.X() = aUpperAligned.Left();
+                else if (aEnd.X() == aUpper.Rigth_())
+                    aPaintEnd.X() = aUpperAligned.Rigth_();
+                if (aEnd.Y() == aUpper.Top())
+                    aPaintEnd.Y() = aUpperAligned.Top();
+                else if (aEnd.Y() == aUpper.Bottom_())

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list