[Libreoffice-commits] core.git: 11 commits - basegfx/source drawinglayer/CppunitTest_drawinglayer_border.mk drawinglayer/qa drawinglayer/source include/basegfx include/drawinglayer include/svx sc/source svx/source sw/source

Armin Le Grand Armin.Le.Grand at cib.de
Fri Sep 15 11:15:57 UTC 2017


 basegfx/source/matrix/b2dhommatrixtools.cxx                        |   14 
 drawinglayer/CppunitTest_drawinglayer_border.mk                    |    1 
 drawinglayer/qa/unit/border.cxx                                    |   81 
 drawinglayer/source/primitive2d/baseprimitive2d.cxx                |    1 
 drawinglayer/source/primitive2d/borderlineprimitive2d.cxx          |  493 +++-
 drawinglayer/source/processor2d/vclpixelprocessor2d.hxx            |    1 
 include/basegfx/matrix/b2dhommatrixtools.hxx                       |    9 
 include/drawinglayer/primitive2d/borderlineprimitive2d.hxx         |   99 
 include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx |    1 
 include/svx/framelink.hxx                                          |  369 ---
 include/svx/framelinkarray.hxx                                     |   44 
 include/svx/sdr/primitive2d/svx_primitivetypes2d.hxx               |   19 
 sc/source/ui/miscdlgs/autofmt.cxx                                  |   21 
 sc/source/ui/view/output.cxx                                       |    9 
 svx/source/dialog/framelink.cxx                                    | 1126 +++++-----
 svx/source/dialog/framelinkarray.cxx                               |  872 +++----
 svx/source/dialog/frmsel.cxx                                       |   37 
 svx/source/inc/frmselimpl.hxx                                      |    1 
 svx/source/table/viewcontactoftableobj.cxx                         |  513 ----
 sw/source/core/layout/paintfrm.cxx                                 |  404 +--
 sw/source/ui/table/tautofmt.cxx                                    |   13 
 21 files changed, 1895 insertions(+), 2233 deletions(-)

New commits:
commit ab65fe804cf3a97bd172b5551b553b9bcde6d756
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Sep 14 16:45:56 2017 +0200

    borderline: Extended decompose
    
    Decompose of BorderLinePrimitive2D extended to take care
    of non-perpendicular line endings for matching. Improved
    matching, one error in calc fixed
    
    Change-Id: I869a75385711b58e6725daba0f22be8a98158ad9

diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 6295d4673c36..0b6dda423adf 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -149,15 +149,118 @@ namespace drawinglayer
                     if(!candidate.isGap())
                     {
                         const basegfx::B2DVector aDeltaY(aPerpendicular * (fOffset + (fWidth * 0.5)));
-                        const basegfx::B2DPoint aStart(getStart() - (aVector * candidate.getStartAverage()) + aDeltaY);
-                        const basegfx::B2DPoint aEnd(getEnd() + (aVector * candidate.getEndAverage()) + aDeltaY);
-
-                        addPolygonStrokePrimitive2D(
-                            rContainer,
-                            aStart,
-                            aEnd,
-                            candidate.getLineAttribute(),
-                            getStrokeAttribute());
+                        const basegfx::B2DPoint aStart(getStart() + aDeltaY);
+                        const basegfx::B2DPoint aEnd(getEnd() + aDeltaY);
+                        const bool bStartPerpendicular(rtl::math::approxEqual(candidate.getStartLeft(), candidate.getStartRight()));
+                        const bool bEndPerpendicular(rtl::math::approxEqual(candidate.getEndLeft(), candidate.getEndRight()));
+
+                        if(bStartPerpendicular && bEndPerpendicular)
+                        {
+                            // start and end extends lead to an edge perpendicular to the line, so we can just use
+                            // a PolygonStrokePrimitive2D for representation
+                            addPolygonStrokePrimitive2D(
+                                rContainer,
+                                aStart - (aVector * candidate.getStartLeft()),
+                                aEnd + (aVector * candidate.getEndLeft()),
+                                candidate.getLineAttribute(),
+                                getStrokeAttribute());
+                        }
+                        else
+                        {
+                            // start and/or end extensions lead to a lineStart/End that is *not*
+                            // perpendicular to the line itself
+                            if(getStrokeAttribute().isDefault() || 0.0 == getStrokeAttribute().getFullDotDashLen())
+                            {
+                                // without stroke, we can simply represent that using a filled polygon
+                                const basegfx::B2DVector aHalfLineOffset(aPerpendicular * (candidate.getLineAttribute().getWidth() * 0.5));
+                                basegfx::B2DPolygon aPolygon;
+
+                                aPolygon.append(aStart - aHalfLineOffset - (aVector * candidate.getStartLeft()));
+                                aPolygon.append(aEnd - aHalfLineOffset + (aVector * candidate.getEndLeft()));
+                                aPolygon.append(aEnd + aHalfLineOffset + (aVector * candidate.getEndRight()));
+                                aPolygon.append(aStart + aHalfLineOffset - (aVector * candidate.getStartRight()));
+
+                                rContainer.push_back(
+                                    new PolyPolygonColorPrimitive2D(
+                                        basegfx::B2DPolyPolygon(aPolygon),
+                                        candidate.getLineAttribute().getColor()));
+                            }
+                            else
+                            {
+                                // with stroke, we have a problem - a filled polygon would lose the
+                                // stroke. Let's represent the start and/or end as triangles, the main
+                                // line still as PolygonStrokePrimitive2D.
+                                // Fill default line Start/End for stroke, so we need no adaptions in else pathes
+                                basegfx::B2DPoint aStrokeStart(aStart - (aVector * candidate.getStartLeft()));
+                                basegfx::B2DPoint aStrokeEnd(aEnd + (aVector * candidate.getEndLeft()));
+                                const basegfx::B2DVector aHalfLineOffset(aPerpendicular * (candidate.getLineAttribute().getWidth() * 0.5));
+
+                                if(!bStartPerpendicular)
+                                {
+                                    const double fMin(std::min(candidate.getStartLeft(), candidate.getStartRight()));
+                                    const double fMax(std::max(candidate.getStartLeft(), candidate.getStartRight()));
+                                    basegfx::B2DPolygon aPolygon;
+
+                                    // create a triangle with min/max values for LineStart and add
+                                    if(rtl::math::approxEqual(candidate.getStartLeft(), fMax))
+                                    {
+                                        aPolygon.append(aStart - aHalfLineOffset - (aVector * candidate.getStartLeft()));
+                                    }
+
+                                    aPolygon.append(aStart - aHalfLineOffset - (aVector * fMin));
+                                    aPolygon.append(aStart + aHalfLineOffset - (aVector * fMin));
+
+                                    if(rtl::math::approxEqual(candidate.getStartRight(), fMax))
+                                    {
+                                        aPolygon.append(aStart + aHalfLineOffset - (aVector * candidate.getStartRight()));
+                                    }
+
+                                    rContainer.push_back(
+                                        new PolyPolygonColorPrimitive2D(
+                                            basegfx::B2DPolyPolygon(aPolygon),
+                                            candidate.getLineAttribute().getColor()));
+
+                                    // Adapt StrokeStart accordingly
+                                    aStrokeStart = aStart - (aVector * fMin);
+                                }
+
+                                if(!bEndPerpendicular)
+                                {
+                                    const double fMin(std::min(candidate.getEndLeft(), candidate.getEndRight()));
+                                    const double fMax(std::max(candidate.getEndLeft(), candidate.getEndRight()));
+                                    basegfx::B2DPolygon aPolygon;
+
+                                    // create a triangle with min/max values for LineEnd and add
+                                    if(rtl::math::approxEqual(candidate.getEndLeft(), fMax))
+                                    {
+                                        aPolygon.append(aEnd - aHalfLineOffset + (aVector * candidate.getEndLeft()));
+                                    }
+
+                                    if(rtl::math::approxEqual(candidate.getEndRight(), fMax))
+                                    {
+                                        aPolygon.append(aEnd + aHalfLineOffset + (aVector * candidate.getEndRight()));
+                                    }
+
+                                    aPolygon.append(aEnd + aHalfLineOffset + (aVector * fMin));
+                                    aPolygon.append(aEnd - aHalfLineOffset + (aVector * fMin));
+
+                                    rContainer.push_back(
+                                        new PolyPolygonColorPrimitive2D(
+                                            basegfx::B2DPolyPolygon(aPolygon),
+                                            candidate.getLineAttribute().getColor()));
+
+                                    // Adapt StrokeEnd accordingly
+                                    aStrokeEnd = aEnd + (aVector * fMin);
+                                }
+
+                                addPolygonStrokePrimitive2D(
+                                    rContainer,
+                                    aStrokeStart,
+                                    aStrokeEnd,
+                                    candidate.getLineAttribute(),
+                                    getStrokeAttribute());
+                            }
+                        }
                     }
 
                     fOffset += fWidth;
diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
index b6634f6ce64e..cb57e40fbe8a 100644
--- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
@@ -79,10 +79,6 @@ namespace drawinglayer
             /// helper to get adapted width (maximum)
             double getAdaptedWidth(double fMinWidth) const;
 
-            /// helper to get average values Start/End
-            double getStartAverage() const { return 0.5 * (mfStartLeft + mfStartRight); }
-            double getEndAverage() const { return 0.5 * (mfEndLeft + mfEndRight); }
-
             /// compare operator
             bool operator==(const BorderLine& rBorderLine) const;
         };
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index da4c342d44d6..858ea99ef83f 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -660,7 +660,7 @@ void ScOutputData::SetCellRotations()
                         const double fOrient((bLayoutRTL ? -1.0 : 1.0) * nAttrRotate * F_PI18000); // 1/100th degrees -> [0..2PI]
                         svx::frame::Array& rArray = mrTabInfo.maArray;
 
-                        rArray.SetCellRotation(nY+1, nX+1, eRotMode, fOrient);
+                        rArray.SetCellRotation(nX+1, nY+1, eRotMode, fOrient);
                     }
                 }
             }
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index ea5b33315cfc..e205560df33c 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -550,12 +550,15 @@ void getAllCutSets(
 
             for(const auto& rOtherOffset : otherOffsets)
             {
-                const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth)));
-                const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth)));
-                CutSet aCutSet;
+                if(0xff != rOtherOffset.maColor.GetTransparency())
+                {
+                    const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth)));
+                    const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth)));
+                    CutSet aCutSet;
 
-                getCutSet(aCutSet, rLeft, rRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector());
-                rCutSets.push_back(aCutSet);
+                    getCutSet(aCutSet, rLeft, rRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector());
+                    rCutSets.push_back(aCutSet);
+                }
             }
         }
     }
@@ -586,22 +589,42 @@ CutSet getMinMaxCutSet(
     {
         const CutSet& rCandidate(rCutSets[a]);
         const double fCandidate(rCandidate.mfOLML + rCandidate.mfORML + rCandidate.mfOLMR + rCandidate.mfORMR);
+        bool bCopy(false);
 
-        if(bMin)
+        if(basegfx::fTools::equalZero(fCandidate - fRetval))
         {
-            if(fCandidate < fRetval)
+            // both are equal (use basegfx::fTools::equalZero and *not* rtl::math::approxEqual here, that is too precise)
+            const bool bPerpendR(rtl::math::approxEqual(aRetval.mfOLML, aRetval.mfOLMR) || rtl::math::approxEqual(aRetval.mfORML, aRetval.mfORMR));
+            const bool bPerpendC(rtl::math::approxEqual(rCandidate.mfOLML, rCandidate.mfOLMR) || rtl::math::approxEqual(rCandidate.mfORML, rCandidate.mfORMR));
+
+            if(!bPerpendR && !bPerpendC)
+            {
+                // when both are not perpend, create medium cut
+                const double fNewOLML(std::max(std::min(rCandidate.mfOLML, rCandidate.mfORML), std::min(aRetval.mfOLML, aRetval.mfORML)));
+                const double fNewORML(std::min(std::max(rCandidate.mfOLML, rCandidate.mfORML), std::max(aRetval.mfOLML, aRetval.mfORML)));
+                const double fNewOLMR(std::max(std::min(rCandidate.mfOLMR, rCandidate.mfORMR), std::min(aRetval.mfOLMR, aRetval.mfORMR)));
+                const double fNewORMR(std::min(std::max(rCandidate.mfOLMR, rCandidate.mfORMR), std::max(aRetval.mfOLMR, aRetval.mfORMR)));
+                aRetval.mfOLML = fNewOLML;
+                aRetval.mfORML = fNewORML;
+                aRetval.mfOLMR = fNewOLMR;
+                aRetval.mfORMR = fNewORMR;
+                fRetval = aRetval.mfOLML + aRetval.mfORML + aRetval.mfOLMR + aRetval.mfORMR;
+            }
+            else
             {
-                fRetval = fCandidate;
-                aRetval = rCandidate;
+                // if equal and perpend differs, perpend one is assumed smaller
+                bCopy = ((bMin && bPerpendC && !bPerpendR) || (!bMin && !bPerpendC && bPerpendR));
             }
         }
         else
         {
-            if(fCandidate > fRetval)
-            {
-                fRetval = fCandidate;
-                aRetval = rCandidate;
-            }
+            bCopy = ((bMin && fCandidate < fRetval) || (!bMin && fCandidate > fRetval));
+        }
+
+        if(bCopy)
+        {
+            fRetval = fCandidate;
+            aRetval = rCandidate;
         }
     }
 
commit 2f16219741aba016677103e4b22738d055c39a91
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Thu Sep 14 11:44:23 2017 +0200

    borderline: Fixed PatternScale
    
    The applied PatternScale factor was not consequently used in
    svx::frame::Style so that the Previews in the Dialogs look weird.
    Fixed that and stumbled over Writer applying it's own scale
    which then was leading to double scaling, ceaned that up.
    
    Change-Id: I89f41bfd7884e5e743080301e219491e215054c3

diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx
index 1b130efa7f2f..414f23aaaca7 100644
--- a/include/svx/framelink.hxx
+++ b/include/svx/framelink.hxx
@@ -159,11 +159,11 @@ public:
     /** Constructs an invisible frame style. */
     explicit Style();
     /** Constructs a frame style with passed line widths. */
-    explicit Style( double nP, double nD, double nS, SvxBorderLineStyle nType );
+    explicit Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale );
     /** Constructs a frame style with passed color and line widths. */
-    explicit Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType );
+    explicit Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale );
     /** Constructs a frame style from the passed SvxBorderLine struct. */
-    explicit Style( const editeng::SvxBorderLine* pBorder, double fScale = 1.0 );
+    explicit Style( const editeng::SvxBorderLine* pBorder, double fScale );
 
     RefMode GetRefMode() const { if(!maImplStyle) return RefMode::Centered; return maImplStyle->meRefMode; }
     const Color GetColorPrim() const { if(!maImplStyle) return Color(); return maImplStyle->maColorPrim; }
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index b7554436bf48..ea5b33315cfc 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -56,19 +56,21 @@ Style::Style() :
 {
 }
 
-Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType ) :
+Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) :
     maImplStyle(new implStyle()),
     mpUsingCell(nullptr)
 {
     maImplStyle->mnType = nType;
+    maImplStyle->mfPatternScale = fScale;
     Set( nP, nD, nS );
 }
 
-Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType ) :
+Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType, double fScale ) :
     maImplStyle(new implStyle()),
     mpUsingCell(nullptr)
 {
     maImplStyle->mnType = nType;
+    maImplStyle->mfPatternScale = fScale;
     Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS );
 }
 
@@ -154,6 +156,7 @@ void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWid
     const sal_uInt16 nSecn(pBorder->GetInWidth());
 
     pTarget->mnType = pBorder->GetBorderLineStyle();
+    pTarget->mfPatternScale = fScale;
 
     if( !nSecn )    // no or single frame border
     {
diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx
index 9678339fbca6..291d47903361 100644
--- a/svx/source/dialog/frmsel.cxx
+++ b/svx/source/dialog/frmsel.cxx
@@ -132,7 +132,7 @@ void FrameBorder::SetCoreStyle( const SvxBorderLine* pStyle )
         maCoreStyle = SvxBorderLine();
 
     // from twips to points
-    maUIStyle.Set( &maCoreStyle, 0.05, FRAMESEL_GEOM_WIDTH );
+    maUIStyle.Set( &maCoreStyle, FrameBorder::GetDefaultPatternScale(), FRAMESEL_GEOM_WIDTH );
     meState = maUIStyle.IsUsed() ? FrameBorderState::Show : FrameBorderState::Hide;
 }
 
@@ -150,7 +150,7 @@ void FrameBorder::SetState( FrameBorderState eState )
         break;
         case FrameBorderState::DontCare:
             maCoreStyle = SvxBorderLine();
-            maUIStyle = frame::Style(3, 0, 0, SvxBorderLineStyle::SOLID); //OBJ_FRAMESTYLE_DONTCARE
+            maUIStyle = frame::Style(3, 0, 0, SvxBorderLineStyle::SOLID, FrameBorder::GetDefaultPatternScale()); //OBJ_FRAMESTYLE_DONTCARE
         break;
     }
 }
@@ -643,7 +643,7 @@ void FrameSelectorImpl::DrawAllFrameBorders()
             rRightStyle.GetColorSecn(), rRightStyle.GetColorGap(),
             rRightStyle.UseGapColor(),
             rRightStyle.Secn(), rRightStyle.Dist(), rRightStyle.Prim( ),
-            rRightStyle.Type( ) );
+            rRightStyle.Type( ), rRightStyle.PatternScale() );
     maArray.SetColumnStyleRight( mbVer ? 1 : 0, rInvertedRight );
 
     maArray.SetRowStyleTop( 0, maTop.GetUIStyle() );
@@ -655,7 +655,7 @@ void FrameSelectorImpl::DrawAllFrameBorders()
             rHorStyle.GetColorSecn(), rHorStyle.GetColorGap(),
             rHorStyle.UseGapColor(),
             rHorStyle.Secn(), rHorStyle.Dist(), rHorStyle.Prim( ),
-            rHorStyle.Type() );
+            rHorStyle.Type(), rHorStyle.PatternScale() );
         maArray.SetRowStyleTop( 1, rInvertedHor );
     }
 
@@ -665,7 +665,7 @@ void FrameSelectorImpl::DrawAllFrameBorders()
             rBottomStyle.GetColorSecn(), rBottomStyle.GetColorGap(),
             rBottomStyle.UseGapColor(),
             rBottomStyle.Secn(), rBottomStyle.Dist(), rBottomStyle.Prim( ),
-            rBottomStyle.Type() );
+            rBottomStyle.Type(), rBottomStyle.PatternScale() );
     maArray.SetRowStyleBottom( mbHor ? 1 : 0, rInvertedBottom );
 
     for( size_t nCol = 0; nCol < maArray.GetColCount(); ++nCol )
diff --git a/svx/source/inc/frmselimpl.hxx b/svx/source/inc/frmselimpl.hxx
index 7e2e73b8238a..62a0d7f3a9d7 100644
--- a/svx/source/inc/frmselimpl.hxx
+++ b/svx/source/inc/frmselimpl.hxx
@@ -36,6 +36,7 @@ class FrameBorder
 {
 public:
     explicit FrameBorder(FrameBorderType eType);
+    static double GetDefaultPatternScale() { return 0.05; }
 
     FrameBorderType GetType() const
     {
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index 89c4351957a8..4098b2add8f4 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2758,20 +2758,11 @@ void SwTabFramePainter::Insert( const SwFrame& rFrame, const SvxBoxItem& rBoxIte
     bool const bVert = mrTabFrame.IsVertical();
     bool const bR2L  = mrTabFrame.IsRightToLeft();
 
-    SwViewShell* pViewShell = mrTabFrame.getRootFrame()->GetCurrShell();
-    OutputDevice* pOutDev = pViewShell->GetOut();
-    const MapMode& rMapMode = pOutDev->GetMapMode();
-    const Fraction& rFracX = rMapMode.GetScaleX();
-    const Fraction& rFracY = rMapMode.GetScaleY();
-
-    svx::frame::Style aL(rBoxItem.GetLeft(), rFracY);
-//    aL.SetPatternScale(rFracY);
-    svx::frame::Style aR(rBoxItem.GetRight(), rFracY);
-//    aR.SetPatternScale(rFracY);
-    svx::frame::Style aT(rBoxItem.GetTop(), rFracX);
-//    aT.SetPatternScale(rFracX);
-    svx::frame::Style aB(rBoxItem.GetBottom(), rFracX);
-//    aB.SetPatternScale(rFracX);
+    // no scaling needed, it's all in the primitives and the target device
+    svx::frame::Style aL(rBoxItem.GetLeft(), 1.0);
+    svx::frame::Style aR(rBoxItem.GetRight(), 1.0);
+    svx::frame::Style aT(rBoxItem.GetTop(), 1.0);
+    svx::frame::Style aB(rBoxItem.GetBottom(), 1.0);
 
     aR.MirrorSelf();
     aB.MirrorSelf();
commit 16fd7af90a9be159ebc7eab09083f1ef7eb64645
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Wed Sep 13 18:37:02 2017 +0200

    borderline: extended the expand logic
    
    Extended and checked the expand logic for creating
    the line extends. Now creating quite the right lines,
    will need to check some speccial cases. Also some
    cleanups.
    
    Change-Id: I3a3bd4d23c7017ecd873147df2d93af61de39fa6

diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index eba1f7f0d996..6295d4673c36 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -165,89 +165,6 @@ namespace drawinglayer
             }
         }
 
-
-
-
-        //         static double fPatScFact(10.0); // 10.0 multiply, see old code
-        //         const std::vector<double> aDashing(svtools::GetLineDashing(getStyle(), getPatternScale() * fPatScFact));
-        //         const attribute::StrokeAttribute aStrokeAttribute(aDashing);
-
-        //         if (3 == getBorderLines().size())
-        //         {
-        //             // double line with gap. Use mfSmallestAllowedDiscreteGapDistance (see get2DDecomposition) as distance.
-        //             // That value is prepared to be at least one pixel (discrete unit) so that the
-        //             // decomposition is view-dependent in this cases
-        //             const BorderLine& rLeft(getBorderLines()[0]);
-        //             const BorderLine& rGap(getBorderLines()[1]);
-        //             const BorderLine& rRight(getBorderLines()[2]);
-        //             const double fFullWidth(rLeft.getWidth() + mfSmallestAllowedDiscreteGapDistance + rRight.getWidth());
-
-        //             {
-        //                 // inside line (left of vector). Create stroke primitive centered on left line width
-        //                 const double fDeltaY((rLeft.getWidth() - fFullWidth) * 0.5);
-        //                 const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
-        //                 const basegfx::B2DPoint aStart(getStart() - (aVector * rLeft.getBorderLineExtend().getStartAverage()) + aDeltaY);
-        //                 const basegfx::B2DPoint aEnd(getEnd() + (aVector * rLeft.getBorderLineExtend().getEndAverage()) + aDeltaY);
-        //                 const attribute::LineAttribute aLineAttribute(rLeft.getRGBColor(), rLeft.getWidth());
-
-        //                 addPolygonStrokePrimitive2D(
-        //                     rContainer,
-        //                     aStart,
-        //                     aEnd,
-        //                     aLineAttribute,
-        //                     aStrokeAttribute);
-        //             }
-
-        //             if (hasGapColor())
-        //             {
-        //                 // gap (if visible, found practical usage in Writer MultiColorBorderLines).
-        //                 // Create stroke primitive on vector with given color centered on gap position
-        //                 const double fDeltaY(((fFullWidth - mfSmallestAllowedDiscreteGapDistance) * 0.5) - rRight.getWidth());
-        //                 const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
-        //                 const basegfx::B2DPoint aStart(getStart() - (aVector * rGap.getBorderLineExtend().getStartAverage()) + aDeltaY);
-        //                 const basegfx::B2DPoint aEnd(getEnd() + (aVector * rGap.getBorderLineExtend().getEndAverage()) + aDeltaY);
-        //                 const attribute::LineAttribute aLineAttribute(rGap.getRGBColor(), mfSmallestAllowedDiscreteGapDistance);
-
-        //                 addPolygonStrokePrimitive2D(
-        //                     rContainer,
-        //                     aStart,
-        //                     aEnd,
-        //                     aLineAttribute,
-        //                     aStrokeAttribute);
-        //             }
-
-        //             {
-        //                 // outside line (right of vector). Create stroke primitive centered on right line width
-        //                 const double fDeltaY((fFullWidth - rRight.getWidth()) * 0.5);
-        //                 const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
-        //                 const basegfx::B2DPoint aStart(getStart() - (aVector * rRight.getBorderLineExtend().getStartAverage()) + aDeltaY);
-        //                 const basegfx::B2DPoint aEnd(getEnd() + (aVector * rRight.getBorderLineExtend().getEndAverage()) + aDeltaY);
-        //                 const attribute::LineAttribute aLineAttribute(rRight.getRGBColor(), rRight.getWidth());
-
-        //                 addPolygonStrokePrimitive2D(
-        //                     rContainer,
-        //                     aStart,
-        //                     aEnd,
-        //                     aLineAttribute,
-        //                     aStrokeAttribute);
-        //             }
-        //         }
-        //         else
-        //         {
-        //             // single line, only inside values used, no vertical offsets
-        //             const BorderLine& rBorderLine(getBorderLines()[0]);
-        //             const attribute::LineAttribute aLineAttribute(rBorderLine.getRGBColor(), rBorderLine.getWidth());
-
-        //             addPolygonStrokePrimitive2D(
-        //                 rContainer,
-        //                 getStart() - (aVector * rBorderLine.getBorderLineExtend().getStartAverage()),
-        //                 getEnd() + (aVector * rBorderLine.getBorderLineExtend().getEndAverage()),
-        //                 aLineAttribute,
-        //                 aStrokeAttribute);
-        //         }
-        //     }
-        // }
-
         bool BorderLinePrimitive2D::isHorizontalOrVertical(const geometry::ViewInformation2D& rViewInformation) const
         {
             if (!getStart().equal(getEnd()))
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index c7a6377ab3e8..b7554436bf48 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -380,6 +380,7 @@ double getOffsetAndHalfWidthAndColorFromStyle(
         Color aSecn(rStyle.GetColorSecn());
         double fPrim(rStyle.Prim());
         double fSecn(rStyle.Secn());
+        const bool bSecnUsed(0.0 != fSecn);
 
         if(bMirrored)
         {
@@ -389,8 +390,12 @@ double getOffsetAndHalfWidthAndColorFromStyle(
                 case RefMode::End: aRefMode = RefMode::Begin; break;
                 default: break;
             }
-            std::swap(aPrim, aSecn);
-            std::swap(fPrim, fSecn);
+
+            if(bSecnUsed)
+            {
+                std::swap(aPrim, aSecn);
+                std::swap(fPrim, fSecn);
+            }
         }
 
         if (RefMode::Centered != aRefMode)
@@ -409,7 +414,7 @@ double getOffsetAndHalfWidthAndColorFromStyle(
             }
         }
 
-        if (rStyle.Dist() && fSecn)
+        if (bSecnUsed)
         {
             // both or all three lines used
             const bool bPrimTransparent(0xff == rStyle.GetColorPrim().GetTransparency());
@@ -503,6 +508,103 @@ void getCutSet(
         &rCutSet.mfORMR);
 }
 
+void getAllCutSets(
+    std::vector< CutSet >& rCutSets,
+    const basegfx::B2DPoint& rOrigin,
+    const basegfx::B2DPoint& rLeft,
+    const basegfx::B2DPoint& rRight,
+    const basegfx::B2DVector& rX,
+    const StyleVectorTable& rStyleVectorTable,
+    bool bUpper,
+    bool bLower)
+{
+    for(const auto& rStyleVectorCombination : rStyleVectorTable)
+    {
+        if(bUpper || bLower)
+        {
+            // use only upper or lower vectors compared to rX
+            const double fCross(rX.cross(rStyleVectorCombination.getB2DVector()));
+
+            if(bUpper && fCross > 0.0)
+            {
+                // upper vectors wanted, but is lower
+                continue;
+            }
+
+            if(bLower && fCross < 0.0)
+            {
+                // lower vectors wanted, but is upper
+                continue;
+            }
+        }
+
+        std::vector< OffsetAndHalfWidthAndColor > otherOffsets;
+        getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets);
+
+        if(!otherOffsets.empty())
+        {
+            const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleVectorCombination.getB2DVector()));
+
+            for(const auto& rOtherOffset : otherOffsets)
+            {
+                const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth)));
+                const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth)));
+                CutSet aCutSet;
+
+                getCutSet(aCutSet, rLeft, rRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector());
+                rCutSets.push_back(aCutSet);
+            }
+        }
+    }
+}
+
+CutSet getMinMaxCutSet(
+    bool bMin,
+    const std::vector< CutSet >& rCutSets)
+{
+    if(rCutSets.empty())
+    {
+        CutSet aRetval;
+        aRetval.mfOLML = aRetval.mfORML = aRetval.mfOLMR = aRetval.mfORMR = 0.0;
+        return aRetval;
+    }
+
+    const size_t aSize(rCutSets.size());
+
+    if(1 == aSize)
+    {
+        return rCutSets[0];
+    }
+
+    CutSet aRetval(rCutSets[0]);
+    double fRetval(aRetval.mfOLML + aRetval.mfORML + aRetval.mfOLMR + aRetval.mfORMR);
+
+    for(size_t a(1); a < aSize; a++)
+    {
+        const CutSet& rCandidate(rCutSets[a]);
+        const double fCandidate(rCandidate.mfOLML + rCandidate.mfORML + rCandidate.mfOLMR + rCandidate.mfORMR);
+
+        if(bMin)
+        {
+            if(fCandidate < fRetval)
+            {
+                fRetval = fCandidate;
+                aRetval = rCandidate;
+            }
+        }
+        else
+        {
+            if(fCandidate > fRetval)
+            {
+                fRetval = fCandidate;
+                aRetval = rCandidate;
+            }
+        }
+    }
+
+    return aRetval;
+}
+
 void getExtends(
     std::vector<ExtendSet>& rExtendSet,                     // target Left/Right values to fill
     const basegfx::B2DPoint& rOrigin,                       // own vector start
@@ -518,41 +620,99 @@ void getExtends(
         for(size_t a(0); a < nOffsets; a++)
         {
             const OffsetAndHalfWidthAndColor& rOffset(rOffsets[a]);
-            ExtendSet& rExt(rExtendSet[a]);
-            bool bExtSet(false);
-            const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (rOffset.mfOffset - rOffset.mfHalfWidth)));
-            const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (rOffset.mfOffset + rOffset.mfHalfWidth)));
 
-            for(const auto& rStyleVectorCombination : rStyleVectorTable)
+            if(0xff != rOffset.maColor.GetTransparency())
             {
-                std::vector< OffsetAndHalfWidthAndColor > otherOffsets;
-                getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets);
+                const basegfx::B2DPoint aLeft(rOrigin + (rPerpendX * (rOffset.mfOffset - rOffset.mfHalfWidth)));
+                const basegfx::B2DPoint aRight(rOrigin + (rPerpendX * (rOffset.mfOffset + rOffset.mfHalfWidth)));
+                std::vector< CutSet > aCutSets;
+                CutSet aResult;
+                bool bResultSet(false);
+
+                if(1 == nOffsets)
+                {
+                    // single line:
+                    // - get all CutSets
+                    // - get minimum values as extension (biggest possible overlap)
+                    getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, false);
 
-                if(!otherOffsets.empty())
+                    if(!aCutSets.empty())
+                    {
+                        aResult = getMinMaxCutSet(true, aCutSets);
+                        bResultSet = true;
+                    }
+                }
+                else
                 {
-                    const basegfx::B2DVector aOtherPerpend(basegfx::getNormalizedPerpendicular(rStyleVectorCombination.getB2DVector()));
+                    // multiple lines
+                    const bool bUpper(a < (nOffsets >> 1));
+                    const bool bLower(a > (nOffsets >> 1));
 
-                    for(const auto& rOtherOffset : otherOffsets)
+                    if(bUpper)
                     {
-                        const basegfx::B2DPoint aOtherLeft(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset - rOtherOffset.mfHalfWidth)));
-                        const basegfx::B2DPoint aOtherRight(rOrigin + (aOtherPerpend * (rOtherOffset.mfOffset + rOtherOffset.mfHalfWidth)));
-                        CutSet aCutSet;
+                        getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, true, false);
+
+                        if(!aCutSets.empty())
+                        {
+                            aResult = getMinMaxCutSet(false, aCutSets);
+                            bResultSet = true;
+                        }
+                        else
+                        {
+                            getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, true);
 
-                        getCutSet(aCutSet, aLeft, aRight, rX, aOtherLeft, aOtherRight, rStyleVectorCombination.getB2DVector());
+                            if(!aCutSets.empty())
+                            {
+                                aResult = getMinMaxCutSet(true, aCutSets);
+                                bResultSet = true;
+                            }
+                        }
+                    }
+                    else if(bLower)
+                    {
+                        getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, true);
 
-                        if(!bExtSet)
+                        if(!aCutSets.empty())
                         {
-                            rExt.mfExtLeft = std::min(aCutSet.mfOLML, aCutSet.mfORML);
-                            rExt.mfExtRight = std::min(aCutSet.mfOLMR, aCutSet.mfORMR);
-                            bExtSet = true;
+                            aResult = getMinMaxCutSet(false, aCutSets);
+                            bResultSet = true;
                         }
                         else
                         {
-                            rExt.mfExtLeft = std::min(rExt.mfExtLeft , std::min(aCutSet.mfOLML, aCutSet.mfORML));
-                            rExt.mfExtRight = std::min(rExt.mfExtRight , std::min(aCutSet.mfOLMR, aCutSet.mfORMR));
+                            getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, true, false);
+
+                            if(!aCutSets.empty())
+                            {
+                                aResult = getMinMaxCutSet(true, aCutSets);
+                                bResultSet = true;
+                            }
+                        }
+                    }
+                    else // middle line
+                    {
+                        getAllCutSets(aCutSets, rOrigin, aLeft, aRight, rX, rStyleVectorTable, false, false);
+
+                        if(!aCutSets.empty())
+                        {
+                            const CutSet aResultMin(getMinMaxCutSet(true, aCutSets));
+                            const CutSet aResultMax(getMinMaxCutSet(false, aCutSets));
+
+                            aResult.mfOLML = (aResultMin.mfOLML + aResultMax.mfOLML) * 0.5;
+                            aResult.mfORML = (aResultMin.mfORML + aResultMax.mfORML) * 0.5;
+                            aResult.mfOLMR = (aResultMin.mfOLMR + aResultMax.mfOLMR) * 0.5;
+                            aResult.mfORMR = (aResultMin.mfORMR + aResultMax.mfORMR) * 0.5;
+                            bResultSet = true;
                         }
                     }
                 }
+
+                if(bResultSet)
+                {
+                    ExtendSet& rExt(rExtendSet[a]);
+
+                    rExt.mfExtLeft = std::min(aResult.mfOLML, aResult.mfORML);
+                    rExt.mfExtRight = std::min(aResult.mfOLMR, aResult.mfORMR);
+                }
             }
         }
     }
@@ -588,9 +748,22 @@ void CreateBorderPrimitives(
 
         if(bHasEndStyles)
         {
-            // create extends for line ends, use inverse point/vector and inverse offsets
-            std::reverse(myOffsets.begin(), myOffsets.end());
-            getExtends(aExtendSetEnd, rOrigin + rX, -rX, -aPerpendX, myOffsets, rEndStyleVectorTable);
+            // Create extends for line ends, use inverse point/vector and inverse offsets.
+            // Offsets need to be inverted for different width of lines. To invert, change
+            // order, but also sign of offset. Do this on a copy since myOffsets will be
+            // used below to create the primitives
+            std::vector< OffsetAndHalfWidthAndColor > myInverseOffsets(myOffsets);
+            std::reverse(myInverseOffsets.begin(), myInverseOffsets.end());
+
+            for(auto& offset : myInverseOffsets)
+            {
+                offset.mfOffset *= -1;
+            }
+
+            getExtends(aExtendSetEnd, rOrigin + rX, -rX, -aPerpendX, myInverseOffsets, rEndStyleVectorTable);
+
+            // also need to reverse the result to apply to the correct lines
+            std::reverse(aExtendSetEnd.begin(), aExtendSetEnd.end());
         }
 
         std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines;
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index db54294640c5..5a526145cd54 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -988,7 +988,7 @@ void HelperCreateVerticalEntry(
 
     if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false));
     if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX, false));
-    if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY, true));
+    if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, -rY, true));
     if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX, true));
     if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX, true));
 
@@ -1002,9 +1002,9 @@ void HelperCreateVerticalEntry(
 
     if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY, false));
     if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX, false));
-    if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY, false));
-    if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX, true));
-    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY, true));
+    if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, rY, false));
+    if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, -rX, true));
+    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX - rY, true));
 
     CreateBorderPrimitives(
         rSequence,
commit 1f02af4dbd13d79647549e1269722e2c0b67fa90
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Wed Sep 13 10:29:29 2017 +0200

    borderline: Added merge BorderLinePrimitive2D
    
    Added BorderLinePrimitive2D merges for Writer and fixes.

diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 5fc3b57fbbda..eba1f7f0d996 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -439,7 +439,15 @@ namespace drawinglayer
                     return Primitive2DReference();
                 }
 
-                if(!rBT.isGap())
+                if(rBT.isGap())
+                {
+                    // when gap, width has to be equal
+                    if(!rtl::math::approxEqual(rBT.getLineAttribute().getWidth(), rBC.getLineAttribute().getWidth()))
+                    {
+                        return Primitive2DReference();
+                    }
+                }
+                else
                 {
                     // when not gap, the line extends have at least reach to the center ( > 0.0),
                     // else there is a extend usage. When > 0.0 they just overlap, no problem
@@ -465,11 +473,18 @@ namespace drawinglayer
                 const BorderLine& rBT(pCandidateA->getBorderLines()[a]);
                 const BorderLine& rBC(pCandidateB->getBorderLines()[a]);
 
-                aMergedBorderLines.push_back(
-                    BorderLine(
-                        rBT.getLineAttribute(),
-                        rBT.getStartLeft(), rBT.getStartRight(),
-                        rBC.getEndLeft(), rBC.getEndRight()));
+                if(rBT.isGap())
+                {
+                    aMergedBorderLines.push_back(rBT);
+                }
+                else
+                {
+                    aMergedBorderLines.push_back(
+                        BorderLine(
+                            rBT.getLineAttribute(),
+                            rBT.getStartLeft(), rBT.getStartRight(),
+                            rBC.getEndLeft(), rBC.getEndRight()));
+                }
             }
 
             return Primitive2DReference(
diff --git a/include/svx/framelinkarray.hxx b/include/svx/framelinkarray.hxx
index 83b6c28d2524..2b06d29a41b2 100644
--- a/include/svx/framelinkarray.hxx
+++ b/include/svx/framelinkarray.hxx
@@ -319,6 +319,11 @@ private:
     std::unique_ptr<ArrayImpl>        mxImpl;
 };
 
+// helper to merge B2DPrimitive(s) in rSource and add to rTarget
+void SVX_DLLPUBLIC HelperMergeInB2DPrimitiveArray(
+    const drawinglayer::primitive2d::Primitive2DContainer& rSource,
+    drawinglayer::primitive2d::Primitive2DContainer& rTarget);
+
 }
 }
 
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index 2d81caebd3a7..db54294640c5 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -249,9 +249,6 @@ struct ArrayImpl
     long                GetColPosition( size_t nCol ) const;
     long                GetRowPosition( size_t nRow ) const;
 
-    long                GetColWidth( size_t nFirstCol, size_t nLastCol ) const;
-    long                GetRowHeight( size_t nFirstRow, size_t nLastRow ) const;
-
     bool                HasCellRotation() const;
 };
 
@@ -375,16 +372,6 @@ long ArrayImpl::GetRowPosition( size_t nRow ) const
     return maYCoords[ nRow ];
 }
 
-long ArrayImpl::GetColWidth( size_t nFirstCol, size_t nLastCol ) const
-{
-    return GetColPosition( nLastCol + 1 ) - GetColPosition( nFirstCol );
-}
-
-long ArrayImpl::GetRowHeight( size_t nFirstRow, size_t nLastRow ) const
-{
-    return GetRowPosition( nLastRow + 1 ) - GetRowPosition( nFirstRow );
-}
-
 bool ArrayImpl::HasCellRotation() const
 {
     // check cell array
diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx
index 52d6ce42b943..90d143665140 100644
--- a/svx/source/table/viewcontactoftableobj.cxx
+++ b/svx/source/table/viewcontactoftableobj.cxx
@@ -208,14 +208,14 @@ namespace sdr
             const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX));
 
             /// Fill top-left Style Table
-            if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY, bHor ? true : false));
-            if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX, bHor ? true : true));
-            if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY, bHor ? false : true));
+            if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY, bHor)); // bHor ? true : false));
+            if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX, true)); // bHor ? true : true));
+            if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY, !bHor)); // bHor ? false : true));
 
             /// Fill bottom-right Style Table
-            if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY, bHor ? true : false));
-            if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX, bHor ? false : false));
-            if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY, bHor ? false : true));
+            if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY, bHor)); // bHor ? true : false));
+            if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX, false)); // bHor ? false : false));
+            if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY, !bHor)); // bHor ? false : true));
 
             CreateBorderPrimitives(
                 rContainer,
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index 4ba2fc11ec57..89c4351957a8 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -88,6 +88,7 @@
 #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>
@@ -2431,7 +2432,8 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
     aUpper.Pos() += pUpper->Frame().Pos();
     SwRect aUpperAligned( aUpper );
     ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev );
-    drawinglayer::primitive2d::Primitive2DContainer aSequence;
+    drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence;
+    drawinglayer::primitive2d::Primitive2DContainer aVerticalSequence;
 
     while ( true )
     {
@@ -2559,7 +2561,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                         if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], aY, false)); // aRFromB
 
                         CreateBorderPrimitives(
-                            aSequence,
+                            aHorizontalSequence,
                             aOrigin,
                             aX,
                             aStyles[ 0 ],
@@ -2589,7 +2591,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                         if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], aY, true)); // aBFromL
 
                         CreateBorderPrimitives(
-                            aSequence,
+                            aVerticalSequence,
                             aOrigin,
                             aX,
                             aStyles[ 0 ],
@@ -2604,6 +2606,14 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
         ++aIter;
     }
 
+    // to stay compatible, create order as it was formally. Also try to
+    // merge primitives as far as possible
+    drawinglayer::primitive2d::Primitive2DContainer aSequence;
+
+    svx::frame::HelperMergeInB2DPrimitiveArray(aHorizontalSequence, aSequence);
+    svx::frame::HelperMergeInB2DPrimitiveArray(aVerticalSequence, aSequence);
+
+    // paint
     mrTabFrame.ProcessPrimitives(aSequence);
 
     // restore output device:
commit 53599a9a183878cdf435f80939f8d301a3909d78
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Tue Sep 12 17:28:54 2017 +0200

    borderline: merge redefined, mirrored Styles
    
    Redefined merge of BorderlinePrimitives, removed old Writer
    stuff for it. Also added support for handling Styles mirrored
    for extension calculations.

diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 9421ed8b249b..5fc3b57fbbda 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -144,7 +144,7 @@ namespace drawinglayer
 
                 for(const auto& candidate : maBorderLines)
                 {
-                    const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance) * 0.5);
+                    const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance));
 
                     if(!candidate.isGap())
                     {
@@ -369,6 +369,116 @@ namespace drawinglayer
         // provide unique ID
         ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
 
+        Primitive2DReference tryMergeBorderLinePrimitive2D(
+            const Primitive2DReference& rCandidateA,
+            const Primitive2DReference& rCandidateB)
+        {
+            // try to cast to BorderLinePrimitive2D
+            const primitive2d::BorderLinePrimitive2D* pCandidateA = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateA.get());
+            const primitive2d::BorderLinePrimitive2D* pCandidateB = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateB.get());
+
+            // we need a comparable BorderLinePrimitive2D
+            if(nullptr == pCandidateA || nullptr == pCandidateB)
+            {
+                return Primitive2DReference();
+            }
+
+            // start of candidate has to match end of this
+            if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
+            {
+                return Primitive2DReference();
+            }
+
+            // candidate A needs a length
+            if(pCandidateA->getStart().equal(pCandidateA->getEnd()))
+            {
+                return Primitive2DReference();
+            }
+
+            // candidate B needs a length
+            if(pCandidateB->getStart().equal(pCandidateB->getEnd()))
+            {
+                return Primitive2DReference();
+            }
+
+            // StrokeAttribute has to be equal
+            if(!(pCandidateA->getStrokeAttribute() == pCandidateB->getStrokeAttribute()))
+            {
+                return Primitive2DReference();
+            }
+
+            // direction has to be equal -> cross product == 0.0
+            const basegfx::B2DVector aVT(pCandidateA->getEnd() - pCandidateA->getStart());
+            const basegfx::B2DVector aVC(pCandidateB->getEnd() - pCandidateB->getStart());
+            if(!rtl::math::approxEqual(0.0, aVC.cross(aVT)))
+            {
+                return Primitive2DReference();
+            }
+
+            // number BorderLines has to be equal
+            const size_t count(pCandidateA->getBorderLines().size());
+            if(count != pCandidateB->getBorderLines().size())
+            {
+                return Primitive2DReference();
+            }
+
+            for(size_t a(0); a < count; a++)
+            {
+                const BorderLine& rBT(pCandidateA->getBorderLines()[a]);
+                const BorderLine& rBC(pCandidateB->getBorderLines()[a]);
+
+                // LineAttribute has to be the same
+                if(!(rBC.getLineAttribute() == rBT.getLineAttribute()))
+                {
+                    return Primitive2DReference();
+                }
+
+                // isGap has to be the same
+                if(rBC.isGap() != rBT.isGap())
+                {
+                    return Primitive2DReference();
+                }
+
+                if(!rBT.isGap())
+                {
+                    // when not gap, the line extends have at least reach to the center ( > 0.0),
+                    // else there is a extend usage. When > 0.0 they just overlap, no problem
+                    if(rBT.getEndLeft() >= 0.0
+                        && rBT.getEndRight() >= 0.0
+                        && rBC.getStartLeft() >= 0.0
+                        && rBC.getStartRight() >= 0.0)
+                    {
+                        // okay
+                    }
+                    else
+                    {
+                        return Primitive2DReference();
+                    }
+                }
+            }
+
+            // all conditions met, create merged primitive
+            std::vector< BorderLine > aMergedBorderLines;
+
+            for(size_t a(0); a < count; a++)
+            {
+                const BorderLine& rBT(pCandidateA->getBorderLines()[a]);
+                const BorderLine& rBC(pCandidateB->getBorderLines()[a]);
+
+                aMergedBorderLines.push_back(
+                    BorderLine(
+                        rBT.getLineAttribute(),
+                        rBT.getStartLeft(), rBT.getStartRight(),
+                        rBC.getEndLeft(), rBC.getEndRight()));
+            }
+
+            return Primitive2DReference(
+                new BorderLinePrimitive2D(
+                    pCandidateA->getStart(),
+                    pCandidateB->getEnd(),
+                    aMergedBorderLines,
+                    pCandidateA->getStrokeAttribute()));
+        }
     } // end of namespace primitive2d
 } // end of namespace drawinglayer
 
diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
index 992347c7dc9b..b6634f6ce64e 100644
--- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
@@ -87,6 +87,13 @@ namespace drawinglayer
             bool operator==(const BorderLine& rBorderLine) const;
         };
 
+        /// helper to try to merge two instances of BorderLinePrimitive2D. If it was possible,
+        /// a merged version is in the returned Primitive2DReference. Lots of preconditions
+        /// have to be met to allow that, see implementation (and maybe even expand)
+        Primitive2DReference DRAWINGLAYER_DLLPUBLIC tryMergeBorderLinePrimitive2D(
+            const Primitive2DReference& rCandidateA,
+            const Primitive2DReference& rCandidateB);
+
         /** BorderLinePrimitive2D class
 
         This is the basic primitive to build frames around objects, e.g. tables.
diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx
index 9ebb4c85e5aa..1b130efa7f2f 100644
--- a/include/svx/framelink.hxx
+++ b/include/svx/framelink.hxx
@@ -213,66 +213,27 @@ public:
 
 inline bool operator>( const Style& rL, const Style& rR ) { return rR.operator<(rL); }
 
-// Various helper functions
-
-/** Checks whether two horizontal frame borders are "connectable".
-
-    Two borders are "connectable" in terms of this function, if both can be
-    drawn with only one call of a border drawing function. This means, the two
-    frame borders must have equal style and color, and none of the other
-    vertical and diagonal frame borders break the lines of the two borders in
-    any way (i.e. two vertical double frame borders would break the horizonal
-    frame borders). Of course this function can be used for vertical frame
-    borders as well.
-
-    The following picture shows the meaning of all passed parameters:
-
-                      \      rTFromT      /
-                        \       |       /
-                   rTFromTL     |   rTFromTR
-                            \   |   /
-                              \ | /
-    ======== rLBorder =========   ========== rRBorder =======
-                              / | \
-                            /   |   \
-                   rBFromBL     |   rBFromBR
-                        /       |       \
-                      /      rBFromB      \
-
-    @return
-        True, if rLBorder and rRBorder can be drawn in one step without
-        interruption at their connection point.
- */
-SVX_DLLPUBLIC bool CheckFrameBorderConnectable(
-    const Style&        rLBorder,       /// Style of the left frame border to connect.
-    const Style&        rRBorder,       /// Style of the right frame border to connect.
-
-    const Style&        rTFromTL,       /// Diagonal frame border from top-left to connection point.
-    const Style&        rTFromT,        /// Vertical frame border from top to connection point.
-    const Style&        rTFromTR,       /// Horizontal frame border from top-right to connection point.
-
-    const Style&        rBFromBL,       /// Diagonal frame border from bottom-left to connection point.
-    const Style&        rBFromB,        /// Vertical frame border from bottom to connection point.
-    const Style&        rBFromBR        /// Horizontal frame border from bottom-right to connection point.
-);
-
-
 // Drawing functions
 
 class SAL_WARN_UNUSED SVX_DLLPUBLIC StyleVectorCombination
 {
 private:
     const Style&                mrStyle;
-    const basegfx::B2DVector&   mrB2DVector;
+    const basegfx::B2DVector    maB2DVector;
+    const bool                  mbMirrored;
+
 
 public:
-    StyleVectorCombination(const Style& rStyle, const basegfx::B2DVector& rB2DVector) :
+    StyleVectorCombination(const Style& rStyle, const basegfx::B2DVector& rB2DVector, bool bMirrored) :
         mrStyle(rStyle),
-        mrB2DVector(rB2DVector)
-    {}
+        maB2DVector(rB2DVector),
+        mbMirrored(bMirrored)
+    {
+    }
 
     const Style& getStyle() const { return mrStyle; }
-    const basegfx::B2DVector& getB2DVector() const { return mrB2DVector; }
+    const basegfx::B2DVector& getB2DVector() const { return maB2DVector; }
+    bool isMirrored() const { return mbMirrored; }
 };
 
 typedef std::vector< StyleVectorCombination > StyleVectorTable;
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index ca66b285f8d4..c7a6377ab3e8 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -88,7 +88,7 @@ void Style::SetPatternScale( double fScale )
 {
     if(!maImplStyle)
     {
-        if(1.0 == fScale)
+        if(rtl::math::approxEqual(1.0, fScale))
         {
             return;
         }
@@ -334,29 +334,6 @@ bool Style::operator<( const Style& rOther) const
     return false;
 }
 
-bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
-        const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR,
-        const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR )
-{
-    return      // returns 1 AND (2a OR 2b)
-        // 1) only, if both frame borders are equal
-        (rLBorder == rRBorder)
-        &&
-        (
-            (
-                // 2a) if the borders are not double, at least one of the vertical must not be double
-                !rLBorder.Secn() && (!rTFromT.Secn() || !rBFromB.Secn())
-            )
-            ||
-            (
-                // 2b) if the borders are double, all other borders must not be double
-                rLBorder.Secn() &&
-                !rTFromTL.Secn() && !rTFromT.Secn() && !rTFromTR.Secn() &&
-                !rBFromBL.Secn() && !rBFromB.Secn() && !rBFromBR.Secn()
-            )
-        );
-}
-
 // Drawing functions
 struct OffsetAndHalfWidthAndColor
 {
@@ -387,48 +364,70 @@ struct ExtendSet
     ExtendSet() : mfExtLeft(0.0), mfExtRight(0.0) {}
 };
 
-void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pForceColor, std::vector< OffsetAndHalfWidthAndColor >& offsets)
+double getOffsetAndHalfWidthAndColorFromStyle(
+    const Style& rStyle,
+    const Color* pForceColor,
+    bool bMirrored,
+    std::vector< OffsetAndHalfWidthAndColor >& offsets)
 {
+    // do not forget RefMode offset, primitive is free of it
+    double fRefModeOffset(0.0);
+
     if (rStyle.IsUsed())
     {
-        // do not forget RefMode offset, primitive is free of it
-        double fRefModeOffset(0.0);
+        RefMode aRefMode(rStyle.GetRefMode());
+        Color aPrim(rStyle.GetColorPrim());
+        Color aSecn(rStyle.GetColorSecn());
+        double fPrim(rStyle.Prim());
+        double fSecn(rStyle.Secn());
+
+        if(bMirrored)
+        {
+            switch(aRefMode)
+            {
+                case RefMode::Begin: aRefMode = RefMode::End; break;
+                case RefMode::End: aRefMode = RefMode::Begin; break;
+                default: break;
+            }
+            std::swap(aPrim, aSecn);
+            std::swap(fPrim, fSecn);
+        }
 
-        if (RefMode::Centered != rStyle.GetRefMode())
+        if (RefMode::Centered != aRefMode)
         {
             const double fHalfWidth(rStyle.GetWidth() * 0.5);
 
-            if (RefMode::Begin == rStyle.GetRefMode())
+            if (RefMode::Begin == aRefMode)
             {
                 // move aligned below vector
                 fRefModeOffset = fHalfWidth;
             }
-            else if (RefMode::End == rStyle.GetRefMode())
+            else if (RefMode::End == aRefMode)
             {
                 // move aligned above vector
                 fRefModeOffset = -fHalfWidth;
             }
         }
 
-        if (rStyle.Dist() && rStyle.Secn())
+        if (rStyle.Dist() && fSecn)
         {
             // both or all three lines used
             const bool bPrimTransparent(0xff == rStyle.GetColorPrim().GetTransparency());
             const bool bDistTransparent(!rStyle.UseGapColor() || 0xff == rStyle.GetColorGap().GetTransparency());
-            const bool bSecnTransparent(0xff == rStyle.GetColorSecn().GetTransparency());
+            const bool bSecnTransparent(0xff == aSecn.GetTransparency());
 
             if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent)
             {
                 const double a(fRefModeOffset - (rStyle.GetWidth() * 0.5));
-                const double b(a + rStyle.Prim());
+                const double b(a + fPrim);
                 const double c(b + rStyle.Dist());
-                const double d(c + rStyle.Secn());
+                const double d(c + fSecn);
 
                 offsets.push_back(
                     OffsetAndHalfWidthAndColor(
                         (a + b) * 0.5,
-                        rStyle.Prim() * 0.5,
-                        nullptr != pForceColor ? *pForceColor : rStyle.GetColorPrim()));
+                        fPrim * 0.5,
+                        nullptr != pForceColor ? *pForceColor : aPrim));
 
                 offsets.push_back(
                     OffsetAndHalfWidthAndColor(
@@ -441,8 +440,8 @@ void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pF
                 offsets.push_back(
                     OffsetAndHalfWidthAndColor(
                         (c + d) * 0.5,
-                        rStyle.Secn() * 0.5,
-                        nullptr != pForceColor ? *pForceColor : rStyle.GetColorSecn()));
+                        fSecn * 0.5,
+                        nullptr != pForceColor ? *pForceColor : aSecn));
             }
         }
         else
@@ -453,11 +452,13 @@ void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pF
                 offsets.push_back(
                     OffsetAndHalfWidthAndColor(
                         fRefModeOffset,
-                        rStyle.Prim() * 0.5,
-                        nullptr != pForceColor ? *pForceColor : rStyle.GetColorPrim()));
+                        fPrim * 0.5,
+                        nullptr != pForceColor ? *pForceColor : aPrim));
             }
         }
     }
+
+    return fRefModeOffset;
 }
 
 void getCutSet(
@@ -525,7 +526,7 @@ void getExtends(
             for(const auto& rStyleVectorCombination : rStyleVectorTable)
             {
                 std::vector< OffsetAndHalfWidthAndColor > otherOffsets;
-                getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, otherOffsets);
+                getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets);
 
                 if(!otherOffsets.empty())
                 {
@@ -568,7 +569,7 @@ void CreateBorderPrimitives(
 {
     // get offset color pairs for  style, one per visible line
     std::vector< OffsetAndHalfWidthAndColor > myOffsets;
-    getOffsetAndHalfWidthAndColorFromStyle(rBorder, pForceColor, myOffsets);
+    const double fRefModeOffset(getOffsetAndHalfWidthAndColorFromStyle(rBorder, pForceColor, false, myOffsets));
     const size_t nOffsets(myOffsets.size());
 
     if(nOffsets)
@@ -624,12 +625,13 @@ void CreateBorderPrimitives(
         static double fPatScFact(10.0); // 10.0 multiply, see old code
         const std::vector<double> aDashing(svtools::GetLineDashing(rBorder.Type(), rBorder.PatternScale() * fPatScFact));
         const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashing);
+        const basegfx::B2DPoint aStart(rOrigin + (aPerpendX * fRefModeOffset));
 
         rTarget.append(
             drawinglayer::primitive2d::Primitive2DReference(
                 new drawinglayer::primitive2d::BorderLinePrimitive2D(
-                    rOrigin,
-                    rOrigin + rX,
+                    aStart,
+                    aStart + rX,
                     aBorderlines,
                     aStrokeAttribute)));
     }
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index 6052c23f3e8a..2d81caebd3a7 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -954,11 +954,11 @@ void HelperCreateHorizontalEntry(
     const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
     StyleVectorTable aStart;
 
-    if(rStartFromTR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromTR, rX - rY));
-    if(rStartLFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromT, -rY));
-    if(rStartLFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromL, -rX));
-    if(rStartLFromB.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromB, rY));
-    if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY));
+    if(rStartFromTR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromTR, rX - rY, false));
+    if(rStartLFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromT, -rY, true));
+    if(rStartLFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromL, -rX, true));
+    if(rStartLFromB.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromB, rY, false));
+    if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false));
 
     // get involved styles at end
     const Style& rEndFromTL(rArray.GetCellStyleBR( col, row - 1 ));
@@ -968,11 +968,11 @@ void HelperCreateHorizontalEntry(
     const Style& rEndFromBL(rArray.GetCellStyleTR( col, row ));
     StyleVectorTable aEnd;
 
-    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX -rY));
-    if(rEndRFromT.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromT, -rY));
-    if(rEndRFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromR, rX));
-    if(rEndRFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromB, rY));
-    if(rEndFromBL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromBL, rY - rX));
+    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX -rY, true));
+    if(rEndRFromT.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromT, -rY, true));
+    if(rEndRFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromR, rX, false));
+    if(rEndRFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromB, rY, false));
+    if(rEndFromBL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromBL, rY - rX, true));
 
     CreateBorderPrimitives(
         rSequence,
@@ -999,11 +999,11 @@ void HelperCreateVerticalEntry(
     const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
     StyleVectorTable aStart;
 
-    if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY));
-    if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX));
-    if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY));
-    if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX));
-    if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX));
+    if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false));
+    if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX, false));
+    if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY, true));
+    if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX, true));
+    if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX, true));
 
     // get involved styles at end
     const Style& rEndFromTL(rArray.GetCellStyleBR( col - 1, row ));
@@ -1013,11 +1013,11 @@ void HelperCreateVerticalEntry(
     const Style& rEndFromTR(rArray.GetCellStyleBL( col, row ));
     StyleVectorTable aEnd;
 
-    if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY));
-    if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX));
-    if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY));
-    if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX));
-    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY));
+    if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY, false));
+    if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX, false));
+    if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY, false));
+    if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX, true));
+    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY, true));
 
     CreateBorderPrimitives(
         rSequence,
@@ -1069,6 +1069,48 @@ void HelperCreateEntry(const Array& rArray, const Style& rStyle, drawinglayer::p
     }
 }
 
+void HelperMergeInB2DPrimitiveArray(
+    const drawinglayer::primitive2d::Primitive2DContainer& rSource,
+    drawinglayer::primitive2d::Primitive2DContainer& rTarget)
+{
+    if(rSource.size() > 1)
+    {
+        drawinglayer::primitive2d::Primitive2DReference aCandidate;
+
+        for(const auto& a : rSource)
+        {
+            if(aCandidate.is())
+            {
+                const drawinglayer::primitive2d::Primitive2DReference aMerge(
+                    drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(aCandidate, a));
+
+                if(aMerge.is())
+                {
+                    aCandidate = aMerge;
+                }
+                else
+                {
+                    rTarget.append(aCandidate);
+                    aCandidate = a;
+                }
+            }
+            else
+            {
+                aCandidate = a;
+            }
+        }
+
+        if(aCandidate.is())
+        {
+            rTarget.append(aCandidate);
+        }
+    }
+    else
+    {
+        rTarget.append(rSource);
+    }
+}
+
 drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
     size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow,
     const Color* pForceColor ) const
@@ -1078,7 +1120,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
 
     // various primitive sequences to collect the different border types
     drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence;
-    drawinglayer::primitive2d::Primitive2DContainer aVerticalSequence;
+    std::vector< drawinglayer::primitive2d::Primitive2DContainer > aVerticalSequences(nLastCol - nFirstCol + 1);
     drawinglayer::primitive2d::Primitive2DContainer aCrossSequence;
 
     for (size_t nRow = nFirstRow; nRow <= nLastRow; ++nRow)
@@ -1131,7 +1173,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
 
                     if(rLeft.IsUsed())
                     {
-                        HelperCreateEntry(*this, rLeft, aVerticalSequence, pForceColor);
+                        HelperCreateEntry(*this, rLeft, aVerticalSequences[nCol - nFirstCol], pForceColor);
                     }
                 }
 
@@ -1141,7 +1183,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
 
                     if(rRight.IsUsed())
                     {
-                        HelperCreateEntry(*this, rRight, aVerticalSequence, pForceColor);
+                        HelperCreateEntry(*this, rRight, aVerticalSequences[nCol - nFirstCol], pForceColor);
                     }
                 }
 
@@ -1156,15 +1198,15 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
 
                         /// Fill top-left Style Table
                         const Style& rTLFromRight(GetCellStyleTop(_nFirstCol, _nFirstRow));
-                        if(rTLFromRight.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromRight, aX));
+                        if(rTLFromRight.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromRight, aX, false));
                         const Style& rTLFromBottom(GetCellStyleLeft(_nFirstCol, _nFirstRow));
-                        if(rTLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromBottom, aY));
+                        if(rTLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromBottom, aY, false));
 
                         /// Fill bottom-right Style Table
                         const Style& rBRFromBottom(GetCellStyleRight(_nLastCol, _nLastRow));
-                        if(rBRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromBottom, -aY));
+                        if(rBRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromBottom, -aY, true));
                         const Style& rBRFromLeft(GetCellStyleBottom(_nLastCol, _nLastRow));
-                        if(rBRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromLeft, -aX));
+                        if(rBRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromLeft, -aX, true));
 
                         CreateBorderPrimitives(
                             aCrossSequence,
@@ -1186,15 +1228,15 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
 
                         /// Fill bottom-left Style Table
                         const Style& rBLFromTop(GetCellStyleLeft(_nFirstCol, _nLastRow));
-                        if(rBLFromTop.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromTop, -aY));
+                        if(rBLFromTop.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromTop, -aY, true));
                         const Style& rBLFromBottom(GetCellStyleBottom(_nFirstCol, _nLastRow));
-                        if(rBLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromBottom, aX));
+                        if(rBLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromBottom, aX, false));
 
                         /// Fill top-right Style Table
                         const Style& rTRFromBottom(GetCellStyleRight(_nLastCol, _nFirstRow));
-                        if(rTRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromBottom, -aY));
+                        if(rTRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromBottom, -aY, true));
                         const Style& rTRFromLeft(GetCellStyleTop(_nLastCol, _nFirstRow));
-                        if(rTRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromLeft, -aX));
+                        if(rTRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromLeft, -aX, false));
 
                         CreateBorderPrimitives(
                             aCrossSequence,
@@ -1211,9 +1253,13 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
         }
     }
 
-    // to stay compatible, create order as it was formally
-    aCrossSequence.append(aHorizontalSequence);
-    aCrossSequence.append(aVerticalSequence);
+    // to stay compatible, create order as it was formally. Also try to
+    // merge primitives as far as possible
+    HelperMergeInB2DPrimitiveArray(aHorizontalSequence, aCrossSequence);
+    for(const auto& aVert : aVerticalSequences)
+    {
+        HelperMergeInB2DPrimitiveArray(aVert, aCrossSequence);
+    }
 
     return aCrossSequence;
 }
diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx
index d696569dc329..52d6ce42b943 100644
--- a/svx/source/table/viewcontactoftableobj.cxx
+++ b/svx/source/table/viewcontactoftableobj.cxx
@@ -197,7 +197,7 @@ namespace sdr
             return svx::frame::Style();
         }
 
-        void createForVector(drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX,
+        void createForVector(bool bHor, drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX,
             const svx::frame::Style& rLine,
             const svx::frame::Style& rLeftA, const svx::frame::Style& rLeftB, const svx::frame::Style& rLeftC,
             const svx::frame::Style& rRightA, const svx::frame::Style& rRightB, const svx::frame::Style& rRightC)
@@ -206,17 +206,16 @@ namespace sdr
             svx::frame::StyleVectorTable aStart;
             svx::frame::StyleVectorTable aEnd;
             const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX));
-            const double fTwipsToMM(127.0 / 72.0);
 
             /// Fill top-left Style Table
-            if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY));
-            if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX));
-            if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY));
+            if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY, bHor ? true : false));
+            if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX, bHor ? true : true));
+            if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY, bHor ? false : true));
 
             /// Fill bottom-right Style Table
-            if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY));
-            if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX));
-            if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY));
+            if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY, bHor ? true : false));
+            if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX, bHor ? false : false));
+            if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY, bHor ? false : true));
 
             CreateBorderPrimitives(
                 rContainer,
@@ -350,32 +349,31 @@ namespace sdr
                                         const basegfx::B2DPoint aOrigin(aCellMatrix * basegfx::B2DPoint(0.0, 0.0));
                                         const basegfx::B2DVector aX(aCellMatrix * basegfx::B2DVector(1.0, 0.0));
                                         const basegfx::B2DVector aY(aCellMatrix * basegfx::B2DVector(0.0, 1.0));
-                                        const double fTwipsToMM(127.0 / 72.0);
 
                                         if(aLeftLine.IsUsed())
                                         {
-                                            createForVector(aBorderSequence, aOrigin, aY, aLeftLine,
+                                            createForVector(false, aBorderSequence, aOrigin, aY, aLeftLine,
                                                 aTopLine, aLeftFromTLine, aTopFromLLine,
                                                 aBottomLine, aLeftFromBLine, aBottomFromLLine);
                                         }
 
                                         if(aBottomLine.IsUsed())
                                         {
-                                            createForVector(aBorderSequence, aOrigin + aY, aX, aBottomLine,
+                                            createForVector(true, aBorderSequence, aOrigin + aY, aX, aBottomLine,
                                                 aLeftLine, aBottomFromLLine, aLeftFromBLine,
                                                 aRightLine, aBottomFromRLine, aRightFromBLine);
                                         }
 
                                         if(aRightLine.IsUsed())
                                         {
-                                            createForVector(aBorderSequence, aOrigin + aX, aY, aRightLine,
+                                            createForVector(false, aBorderSequence, aOrigin + aX, aY, aRightLine,
                                                 aTopFromRLine, aRightFromTLine, aTopLine,
                                                 aBottomFromRLine, aRightFromBLine, aBottomLine);
                                         }
 
                                         if(aTopLine.IsUsed())
                                         {
-                                            createForVector(aBorderSequence, aOrigin, aX, aTopLine,
+                                            createForVector(true, aBorderSequence, aOrigin, aX, aTopLine,
                                                 aLeftFromTLine, aTopFromLLine, aLeftLine,
                                                 aRightFromTLine, aTopFromRLine, aRightLine);
                                         }
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index ac2d3ba9e21f..4ba2fc11ec57 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -221,7 +221,7 @@ class BorderLines
 {
     drawinglayer::primitive2d::Primitive2DContainer m_Lines;
 public:
-    void AddBorderLine(css::uno::Reference<BorderLinePrimitive2D> const& xLine, SwPaintProperties const & properties);
+    void AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine);
     drawinglayer::primitive2d::Primitive2DContainer GetBorderLines_Clear()
     {
         drawinglayer::primitive2d::Primitive2DContainer lines;
@@ -472,197 +472,20 @@ SwSavePaintStatics::~SwSavePaintStatics()
     gProp.aSScaleY            = aSScaleY;
 }
 
-/**
- * Check whether the two primitive can be merged
- *
- * @param[in]   mergeA  A primitive start and end position
- * @param[in]   mergeB  B primitive start and end position
- * @return      1       if A and B can be merged to a primite staring with A, ending with B
- *              2       if A and B can be merged to a primite staring with B, ending with A
- *              0       if A and B can't be merged
-**/
-static sal_uInt8 lcl_TryMergeLines(
-    pair<double, double> const& mergeA,
-    pair<double, double> const& mergeB,
-    SwPaintProperties const & properties)
-{
-    double const fMergeGap(properties.nSPixelSzW + properties.nSHalfPixelSzW); // NOT static!
-    // A is above/before B
-    if( mergeA.second <= mergeB.first &&
-        mergeA.second + fMergeGap >= mergeB.first )
-    {
-        return 1;
-    }
-    // B is above/before A
-    else if( mergeB.second <= mergeA.first &&
-             mergeB.second + fMergeGap >= mergeA.first )
-    {
-        return 2;
-    }
-    return 0;
-}
-
-/**
- * Make a new primitive from the two input borderline primitive
- *
- * @param[in]   rLine       starting primitive
- * @param[in]   rOther      ending primitive
- * @param[in]   rStart      starting point of merged primitive
- * @param[in]   rEnd        ending point of merged primitive
- * @return      merged primitive
-**/
-static rtl::Reference<BorderLinePrimitive2D>
-lcl_MergeBorderLines(
-    BorderLinePrimitive2D const& rLine,
-    BorderLinePrimitive2D const& rOther,
-    basegfx::B2DPoint const& rStart,
-    basegfx::B2DPoint const& rEnd)
-{
-    const std::vector< BorderLine >& rLineLeft(rLine.getBorderLines());
-    const std::vector< BorderLine >& rOtherLeft(rOther.getBorderLines());
-    const size_t aSize(std::min(rLineLeft.size(), rOtherLeft.size()));
-    std::vector< BorderLine > aNew;
-
-    for(size_t a(0); a < aSize; a++)
-    {
-        const BorderLine& la(rLineLeft[a]);
-        const BorderLine& lb(rOtherLeft[a]);
-
-        if(la.isGap() || lb.isGap())
-        {
-            aNew.push_back(la);
-        }
-        else
-        {
-            aNew.push_back(
-                BorderLine(
-                    la.getLineAttribute(),
-                    la.getStartLeft(),
-                    la.getStartRight(),
-                    lb.getEndLeft(),
-                    lb.getEndRight()));
-        }
-    }
-
-    return new BorderLinePrimitive2D(
-        rStart,
-        rEnd,
-        aNew,
-        rLine.getStrokeAttribute());
-}
-
-/**
- * Merge the two borderline if possible.
- *
- * @param[in]   rThis   one borderline primitive
- * @param[in]   rOther  other borderline primitive
- * @return      merged borderline including the two input primitive, if they can be merged
- *              0, otherwise
-**/
-static rtl::Reference<BorderLinePrimitive2D>
-lcl_TryMergeBorderLine(BorderLinePrimitive2D const& rThis,
-                       BorderLinePrimitive2D const& rOther,
-                       SwPaintProperties const & properties)
+void BorderLines::AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine)
 {
-    assert(rThis.getEnd().getX() >= rThis.getStart().getX());
-    assert(rThis.getEnd().getY() >= rThis.getStart().getY());
-    assert(rOther.getEnd().getX() >= rOther.getStart().getX());
-    assert(rOther.getEnd().getY() >= rOther.getStart().getY());
-    const bool bSameEdgeNumber(rThis.getBorderLines().size() == rOther.getBorderLines().size());
-
-    if (!bSameEdgeNumber)
-    {
-        return nullptr;
-    }
-
-    double thisHeight = rThis.getEnd().getY() - rThis.getStart().getY();
-    double thisWidth  = rThis.getEnd().getX() - rThis.getStart().getX();
-    double otherHeight = rOther.getEnd().getY() -  rOther.getStart().getY();
-    double otherWidth  = rOther.getEnd().getX() -  rOther.getStart().getX();
-
-    // check for same orientation, same line width, same style and matching colors
-    bool bSameStuff(
-        ((thisHeight > thisWidth) == (otherHeight > otherWidth))
-        && rThis.getStrokeAttribute() == rOther.getStrokeAttribute());
-
-    if(bSameStuff)
+    for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend(); ++it)
     {
-        const std::vector< BorderLine >& rLineLeft(rThis.getBorderLines());
-        const std::vector< BorderLine >& rOtherLeft(rOther.getBorderLines());
-        const size_t aSize(std::min(rLineLeft.size(), rOtherLeft.size()));
-
-        for(size_t a(0); bSameStuff && a < aSize; a++)
-        {
-            const BorderLine& la(rLineLeft[a]);
-            const BorderLine& lb(rOtherLeft[a]);
-
-            bSameStuff = la == lb;
-        }
-    }
-
-    if (bSameStuff)
-    {
-        int nRet = 0;
-        if (thisHeight > thisWidth) // vertical line
-        {
-            if (rtl::math::approxEqual(rThis.getStart().getX(), rOther.getStart().getX()))
-            {
-                assert(rtl::math::approxEqual(rThis.getEnd().getX(), rOther.getEnd().getX()));
-                nRet = lcl_TryMergeLines(
-                    make_pair(rThis.getStart().getY(), rThis.getEnd().getY()),
-                    make_pair(rOther.getStart().getY(),rOther.getEnd().getY()),
-                    properties);
-            }
-        }
-        else // horizontal line
-        {
-            if (rtl::math::approxEqual(rThis.getStart().getY(), rOther.getStart().getY()))
-            {
-                assert(rtl::math::approxEqual(rThis.getEnd().getY(), rOther.getEnd().getY()));
-                nRet = lcl_TryMergeLines(
-                    make_pair(rThis.getStart().getX(), rThis.getEnd().getX()),
-                    make_pair(rOther.getStart().getX(),rOther.getEnd().getX()),
-                    properties);
-            }
-        }
+        const drawinglayer::primitive2d::Primitive2DReference aMerged(drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(*it, rLine));
 
-        // The merged primitive starts with rThis and ends with rOther
-        if (nRet == 1)
-        {
-            basegfx::B2DPoint const start(
-                rThis.getStart().getX(), rThis.getStart().getY());
-            basegfx::B2DPoint const end(
-                rOther.getEnd().getX(), rOther.getEnd().getY());
-            return lcl_MergeBorderLines(rThis, rOther, start, end).get();
-        }
-        // The merged primitive starts with rOther and ends with rThis
-        else if(nRet == 2)
+        if (aMerged.is())
         {
-            basegfx::B2DPoint const start(
-                rOther.getStart().getX(), rOther.getStart().getY());
-            basegfx::B2DPoint const end(
-                rThis.getEnd().getX(), rThis.getEnd().getY());
-            return lcl_MergeBorderLines(rOther, rThis, start, end).get();
-        }
-    }
-    return nullptr;
-}
-
-void BorderLines::AddBorderLine(
-        css::uno::Reference<BorderLinePrimitive2D> const& xLine, SwPaintProperties const & properties)
-{
-    for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend();
-         ++it)
-    {
-        rtl::Reference<BorderLinePrimitive2D> const xMerged(
-            lcl_TryMergeBorderLine(*static_cast<BorderLinePrimitive2D*>((*it).get()), *xLine.get(), properties).get());
-        if (xMerged.is())
-        {
-            *it = xMerged.get(); // replace existing line with merged
+            *it = aMerged; // replace existing line with merged // lcl_TryMergeBorderLine
             return;
         }
     }
-    m_Lines.push_back(xLine);
+
+    m_Lines.append(rLine);
 }
 
 SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyl,
@@ -2608,6 +2431,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
     aUpper.Pos() += pUpper->Frame().Pos();
     SwRect aUpperAligned( aUpper );
     ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev );
+    drawinglayer::primitive2d::Primitive2DContainer aSequence;
 
     while ( true )
     {
@@ -2715,8 +2539,6 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
 
             if(aStyles[0].IsUsed())
             {
-                drawinglayer::primitive2d::Primitive2DContainer aSequence;
-
                 if (bHori)
                 {
                     const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
@@ -2728,13 +2550,13 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                         svx::frame::StyleVectorTable aStartTable;
                         svx::frame::StyleVectorTable aEndTable;
 
-                        if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], -aY)); // aLFromT
-                        if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX)); // aLFromL
-                        if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], aY)); // aLFromB
+                        if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], -aY, true)); // aLFromT
+                        if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX, true)); // aLFromL
+                        if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], aY, false)); // aLFromB
 
-                        if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], -aY)); // aRFromT
-                        if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX)); // aRFromR
-                        if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], aY)); // aRFromB
+                        if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], -aY, true)); // aRFromT
+                        if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX, false)); // aRFromR
+                        if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], aY, false)); // aRFromB
 
                         CreateBorderPrimitives(
                             aSequence,
@@ -2743,7 +2565,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                             aStyles[ 0 ],
                             aStartTable,
                             aEndTable,
-                            nullptr
+                            pTmpColor
                         );
                     }
                 }
@@ -2758,13 +2580,13 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                         svx::frame::StyleVectorTable aStartTable;
                         svx::frame::StyleVectorTable aEndTable;
 
-                        if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], -aY)); // aTFromR
-                        if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX)); // aTFromT
-                        if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], aY)); // aTFromL
+                        if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], -aY, false)); // aTFromR
+                        if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX, true)); // aTFromT
+                        if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], aY, true)); // aTFromL
 
-                        if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], -aY)); // aBFromR
-                        if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX)); // aBFromB
-                        if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], aY)); // aBFromL
+                        if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], -aY, false)); // aBFromR
+                        if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX, false)); // aBFromB
+                        if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], aY, true)); // aBFromL
 
                         CreateBorderPrimitives(
                             aSequence,
@@ -2773,18 +2595,17 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                             aStyles[ 0 ],
                             aStartTable,
                             aEndTable,
-                            nullptr
+                            pTmpColor
                         );
                     }
                 }
-
-                mrTabFrame.ProcessPrimitives(aSequence);
             }
         }
-
         ++aIter;
     }
 
+    mrTabFrame.ProcessPrimitives(aSequence);
+
     // restore output device:
     rDev.SetDrawMode( nOldDrawMode );
 }
@@ -4839,7 +4660,7 @@ static void lcl_MakeBorderLine(SwRect const& rRect,
     // When rendering to very small (virtual) devices, like when producing
     // page thumbnails in a mobile device app, the line geometry can end up
     // bogus (negative width or height), so just ignore such border lines.
-    // Otherwise we will run into assertions later in lcl_TryMergeBorderLine()
+    // Otherwise we will run into assertions later in BorderLinePrimitive2D::tryMerge()
     // at least.
     if (aEnd.getX() < aStart.getX() ||
         aEnd.getY() < aStart.getY())
@@ -4894,14 +4715,14 @@ static void lcl_MakeBorderLine(SwRect const& rRect,
                 nExtentRightEnd));
     }
 
-    rtl::Reference<BorderLinePrimitive2D> xLine(
+    drawinglayer::primitive2d::Primitive2DReference aLine(
         new BorderLinePrimitive2D(
             aStart,
             aEnd,
             aBorderlines,
             aStrokeAttribute));
 
-    properties.pBLines->AddBorderLine(xLine.get(), properties);
+    properties.pBLines->AddBorderLine(aLine);
 }
 
 /**
commit 98ceb50c0a65708729df8f2967e616f52db42261
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Fri Sep 8 13:39:29 2017 +0200

    borderline: Adapted BorderLinePrimitive2D and usages
    

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list