[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - 10 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 18:17:51 UTC 2017


 basegfx/source/matrix/b2dhommatrixtools.cxx                        |   14 
 drawinglayer/CppunitTest_drawinglayer_border.mk                    |    2 
 drawinglayer/qa/unit/border.cxx                                    |   94 
 drawinglayer/source/primitive2d/baseprimitive2d.cxx                |    1 
 drawinglayer/source/primitive2d/borderlineprimitive2d.cxx          |  382 ++-
 drawinglayer/source/processor2d/vclpixelprocessor2d.hxx            |    1 
 include/basegfx/matrix/b2dhommatrixtools.hxx                       |    9 
 include/drawinglayer/primitive2d/borderlineprimitive2d.hxx         |  105 
 include/drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx |    1 
 include/svx/framelink.hxx                                          |  407 ---
 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                                       |    7 
 svx/source/dialog/framelink.cxx                                    | 1106 +++++-----
 svx/source/dialog/framelinkarray.cxx                               |  872 +++----
 svx/source/dialog/frmsel.cxx                                       |   37 
 svx/source/inc/frmselimpl.hxx                                      |    1 
 svx/source/table/viewcontactoftableobj.cxx                         |  525 ----
 sw/source/core/layout/paintfrm.cxx                                 |  404 +--
 sw/source/ui/table/tautofmt.cxx                                    |   13 
 21 files changed, 1776 insertions(+), 2289 deletions(-)

New commits:
commit 2d76cfe80755d97214d0841a987cd740e2e9fafa
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 e506d5dae84e..2e7fb0534cab 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, editeng::SvxBorderStyle nType );
+    explicit Style( double nP, double nD, double nS, editeng::SvxBorderStyle 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, editeng::SvxBorderStyle nType );
+    explicit Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, editeng::SvxBorderStyle 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::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 2bd1ae0d1b72..16b0061c3e0a 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, SvxBorderStyle nType ) :
+Style::Style( double nP, double nD, double nS, SvxBorderStyle 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, SvxBorderStyle nType ) :
+Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderStyle 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 8f9928ea5714..16740e44503c 100644
--- a/svx/source/dialog/frmsel.cxx
+++ b/svx/source/dialog/frmsel.cxx
@@ -134,7 +134,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() ? FRAMESTATE_SHOW : FRAMESTATE_HIDE;
 }
 
@@ -152,7 +152,7 @@ void FrameBorder::SetState( FrameBorderState eState )
         break;
         case FRAMESTATE_DONTCARE:
             maCoreStyle = SvxBorderLine();
-            maUIStyle = frame::Style(3, 0, 0, table::BorderLineStyle::SOLID); //OBJ_FRAMESTYLE_DONTCARE
+            maUIStyle = frame::Style(3, 0, 0, table::BorderLineStyle::SOLID, FrameBorder::GetDefaultPatternScale()); //OBJ_FRAMESTYLE_DONTCARE
         break;
     }
 }
@@ -631,7 +631,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() );
@@ -643,7 +643,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 );
     }
 
@@ -653,7 +653,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 a6dacd4527ce..0cbc88071e44 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; }
 
     inline FrameBorderType GetType() const
     {
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index 70527a842861..c6ab47ea5240 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2756,20 +2756,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 d3b6d2dd2707ee9ca54a29c3788cf56b925c4610
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 ecd8575305e4..11926329ebc2 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -177,89 +177,6 @@ namespace drawinglayer
             return aContainer;
         }
 
-
-
-
-        //         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 8f96141be74c..2bd1ae0d1b72 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 f288eeaf4d47..4c9545588326 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -1000,7 +1000,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));
 
@@ -1014,9 +1014,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 0a59a23dec5071c333e5fda635d90abd729f8726
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 ba527c4c9973..ecd8575305e4 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -451,7 +451,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
@@ -477,11 +485,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 673988404fb0..ad7ca1caf10c 100644
--- a/include/svx/framelinkarray.hxx
+++ b/include/svx/framelinkarray.hxx
@@ -327,6 +327,11 @@ private:
     ArrayImplPtr        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 8001882aa1c0..f288eeaf4d47 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 d3b0499a574c..570c3ab40017 100644
--- a/svx/source/table/viewcontactoftableobj.cxx
+++ b/svx/source/table/viewcontactoftableobj.cxx
@@ -211,14 +211,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 7f219bd1ba0e..70527a842861 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>
@@ -2429,7 +2430,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 )
     {
@@ -2557,7 +2559,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 ],
@@ -2587,7 +2589,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 ],
@@ -2602,6 +2604,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 eb0a3a4f7ab47c95c7bd242094b5060087576e90
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.
    
    Change-Id: I5ec65260cde26c88e6e014d910b44c75ea0dc56d

diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 83abdab79b53..ba527c4c9973 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -154,7 +154,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())
                     {
@@ -381,6 +381,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 2e833b1050d4..9455c57bb3d5 100644
--- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
@@ -91,6 +91,13 @@ namespace drawinglayer
             virtual 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 3f73508f15f4..e506d5dae84e 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 follong 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 a0e020e1bc0e..8f96141be74c 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.push_back(
             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 00eadc33a80e..8001882aa1c0 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -966,11 +966,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 ));
@@ -980,11 +980,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,
@@ -1011,11 +1011,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 ));
@@ -1025,11 +1025,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,
@@ -1081,6 +1081,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.push_back(aCandidate);
+                    aCandidate = a;
+                }
+            }
+            else
+            {
+                aCandidate = a;
+            }
+        }
+
+        if(aCandidate.is())
+        {
+            rTarget.push_back(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
@@ -1090,7 +1132,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)
@@ -1143,7 +1185,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
 
                     if(rLeft.IsUsed())
                     {
-                        HelperCreateEntry(*this, rLeft, aVerticalSequence, pForceColor);
+                        HelperCreateEntry(*this, rLeft, aVerticalSequences[nCol - nFirstCol], pForceColor);
                     }
                 }
 
@@ -1153,7 +1195,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
 
                     if(rRight.IsUsed())
                     {
-                        HelperCreateEntry(*this, rRight, aVerticalSequence, pForceColor);
+                        HelperCreateEntry(*this, rRight, aVerticalSequences[nCol - nFirstCol], pForceColor);
                     }
                 }
 
@@ -1168,15 +1210,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,
@@ -1198,15 +1240,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,
@@ -1223,9 +1265,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 d7ce7ab18aed..d3b0499a574c 100644
--- a/svx/source/table/viewcontactoftableobj.cxx
+++ b/svx/source/table/viewcontactoftableobj.cxx
@@ -200,7 +200,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)
@@ -211,14 +211,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));
-            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,
@@ -355,28 +355,28 @@ namespace sdr
 
                                         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 91d4f8e2b880..7f219bd1ba0e 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -213,7 +213,7 @@ class BorderLines
 {
     drawinglayer::primitive2d::Primitive2DContainer m_Lines;
 public:
-    void AddBorderLine(css::uno::Reference<BorderLinePrimitive2D> const& xLine, SwPaintProperties& properties);
+    void AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine);
     drawinglayer::primitive2d::Primitive2DContainer GetBorderLines_Clear()
     {
         drawinglayer::primitive2d::Primitive2DContainer lines;
@@ -464,197 +464,20 @@ SwSavePaintStatics::~SwSavePaintStatics()
     gProp.aSScaleY            = aSScaleY;
 }
 
-/**
- * Check whether the two primitve 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& 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 css::uno::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 css::uno::Reference<BorderLinePrimitive2D>
-lcl_TryMergeBorderLine(BorderLinePrimitive2D const& rThis,
-                       BorderLinePrimitive2D const& rOther,
-                       SwPaintProperties& 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);
-        }
-        // 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);
-        }
-    }
-    return nullptr;
-}
-
-void BorderLines::AddBorderLine(
-        css::uno::Reference<BorderLinePrimitive2D> const& xLine, SwPaintProperties& properties)
-{
-    for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend();
-         ++it)
-    {
-        css::uno::Reference<BorderLinePrimitive2D> const xMerged(
-            lcl_TryMergeBorderLine(*static_cast<BorderLinePrimitive2D*>((*it).get()), *xLine.get(), properties));
-        if (xMerged.is())
-        {
-            *it = xMerged; // replace existing line with merged
+            *it = aMerged; // replace existing line with merged // lcl_TryMergeBorderLine
             return;
         }
     }
-    m_Lines.push_back(xLine);
+
+    m_Lines.push_back(rLine);
 }
 
 SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderStyle nStyl,
@@ -2606,6 +2429,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 )
     {
@@ -2713,8 +2537,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());
@@ -2726,13 +2548,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,
@@ -2741,7 +2563,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                             aStyles[ 0 ],
                             aStartTable,
                             aEndTable,
-                            nullptr
+                            pTmpColor
                         );
                     }
                 }
@@ -2756,13 +2578,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,
@@ -2771,18 +2593,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 );
 }
@@ -4831,7 +4652,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())
@@ -4886,14 +4707,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 0d0a2271ca554c8bf642445bab2bc1be55dd269a
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Fri Sep 8 13:39:29 2017 +0200

    borderline: Adapted BorderLinePrimitive2D and usages
    
    Big changes to BorderLinePrimitive2D and BorderLine, freeing
    it from one/three entries, going to a free definition using
    gaps with width but without color. Adapted usages and creation,
    not yet tested much
    
    Change-Id: Ic1255a790401901c3166d200205bc23322b37185

diff --git a/drawinglayer/CppunitTest_drawinglayer_border.mk b/drawinglayer/CppunitTest_drawinglayer_border.mk
index ea72b8cee602..68ad8488ea15 100644
--- a/drawinglayer/CppunitTest_drawinglayer_border.mk
+++ b/drawinglayer/CppunitTest_drawinglayer_border.mk
@@ -25,6 +25,8 @@ $(eval $(call gb_CppunitTest_use_libraries,drawinglayer_border, \
 	test \
 	tl \
 	$(gb_UWINAPI) \
+	unotest \
+	svt \
 ))
 
 $(eval $(call gb_CppunitTest_use_externals,drawinglayer_border,\
diff --git a/drawinglayer/qa/unit/border.cxx b/drawinglayer/qa/unit/border.cxx
index d3ce2b94173a..229adb28d573 100644
--- a/drawinglayer/qa/unit/border.cxx
+++ b/drawinglayer/qa/unit/border.cxx
@@ -23,6 +23,8 @@
 #include <test/bootstrapfixture.hxx>
 #include <vcl/vclptr.hxx>
 #include <vcl/virdev.hxx>
+#include <editeng/borderline.hxx>
+#include <svtools/borderhelper.hxx>
 
 using namespace com::sun::star;
 
@@ -47,39 +49,48 @@ void DrawinglayerBorderTest::testDoubleDecompositionSolid()
     // 1.47 pixels is 0.03cm at 130% zoom and 96 DPI.
     basegfx::B2DPoint aStart(0, 20);
     basegfx::B2DPoint aEnd(100, 20);
-    double fLeftWidth = 1.47;
-    double fDistance = 1.47;
-    double fRightWidth = 1.47;
-    double fExtendLeftStart = 0;
-    double fExtendLeftEnd = 0;
-    double fExtendRightStart = 0;
-    double fExtendRightEnd = 0;
+    double const fLeftWidth = 1.47;
+    double const fDistance = 1.47;
+    double const fRightWidth = 1.47;
+    double const fExtendLeftStart = 0;
+    double const fExtendLeftEnd = 0;
+    double const fExtendRightStart = 0;
+    double const fExtendRightEnd = 0;
     basegfx::BColor aColorRight;
     basegfx::BColor aColorLeft;
-    basegfx::BColor aColorGap;
-    bool const bHasGapColor = false;
-    const sal_Int16 nStyle = table::BorderLineStyle::DOUBLE;
+    const std::vector<double> aDashing(svtools::GetLineDashing(table::BorderLineStyle::DOUBLE, 10.0));
+    const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashing);
+    std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines;
+
+    aBorderlines.push_back(
+        drawinglayer::primitive2d::BorderLine(
+            drawinglayer::attribute::LineAttribute(
+                aColorLeft,
+                fLeftWidth),
+            fExtendLeftStart,
+            fExtendLeftStart,
+            fExtendLeftEnd,
+            fExtendLeftEnd));
+
+    aBorderlines.push_back(
+        drawinglayer::primitive2d::BorderLine(fDistance));
+
+    aBorderlines.push_back(
+        drawinglayer::primitive2d::BorderLine(
+            drawinglayer::attribute::LineAttribute(
+                aColorRight,
+                fRightWidth),
+            fExtendRightStart,
+            fExtendRightStart,
+            fExtendRightEnd,
+            fExtendRightEnd));
+
     rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> aBorder(
         new drawinglayer::primitive2d::BorderLinePrimitive2D(
             aStart,
             aEnd,
-            drawinglayer::primitive2d::BorderLine(
-                fLeftWidth,
-                aColorLeft,
-                drawinglayer::primitive2d::BorderLineExtend(
-                    fExtendLeftStart,
-                    fExtendLeftEnd)),
-            drawinglayer::primitive2d::BorderLine(
-                fDistance,
-                aColorGap),
-            drawinglayer::primitive2d::BorderLine(
-                fRightWidth,
-                aColorRight,
-                drawinglayer::primitive2d::BorderLineExtend(
-                    fExtendRightStart,
-                    fExtendRightEnd)),
-            bHasGapColor,
-            nStyle));
+            aBorderlines,
+            aStrokeAttribute));
 
     // Decompose it into polygons.
     drawinglayer::geometry::ViewInformation2D aView;
@@ -123,33 +134,42 @@ void DrawinglayerBorderTest::testDoublePixelProcessing()
     double const fExtendRightEnd = 0;
     basegfx::BColor aColorRight;
     basegfx::BColor aColorLeft;
-    basegfx::BColor aColorGap;
-    bool const bHasGapColor = false;
-    const sal_Int16 nStyle = table::BorderLineStyle::DOUBLE;
-    rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> xBorder(
+    const std::vector<double> aDashing(svtools::GetLineDashing(table::BorderLineStyle::DOUBLE, 10.0));
+    const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashing);
+    std::vector< drawinglayer::primitive2d::BorderLine > aBorderlines;
+
+    aBorderlines.push_back(
+        drawinglayer::primitive2d::BorderLine(
+            drawinglayer::attribute::LineAttribute(
+                aColorLeft,
+                fLeftWidth),
+            fExtendLeftStart,
+            fExtendLeftStart,
+            fExtendLeftEnd,
+            fExtendLeftEnd));
+
+    aBorderlines.push_back(
+        drawinglayer::primitive2d::BorderLine(fDistance));
+
+    aBorderlines.push_back(
+        drawinglayer::primitive2d::BorderLine(
+            drawinglayer::attribute::LineAttribute(
+                aColorRight,
+                fRightWidth),
+            fExtendRightStart,
+            fExtendRightStart,
+            fExtendRightEnd,
+            fExtendRightEnd));
+
+    rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> aBorder(
         new drawinglayer::primitive2d::BorderLinePrimitive2D(
             aStart,
             aEnd,
-            drawinglayer::primitive2d::BorderLine(
-                fLeftWidth,
-                aColorLeft,
-                drawinglayer::primitive2d::BorderLineExtend(
-                    fExtendLeftStart,
-                    fExtendLeftEnd)),
-            drawinglayer::primitive2d::BorderLine(
-                fDistance,
-                aColorGap),
-            drawinglayer::primitive2d::BorderLine(
-                fRightWidth,
-                aColorRight,
-                drawinglayer::primitive2d::BorderLineExtend(
-                    fExtendRightStart,
-                    fExtendRightEnd)),
-            bHasGapColor,
-            nStyle));
+            aBorderlines,
+            aStrokeAttribute));
 
     drawinglayer::primitive2d::Primitive2DContainer aPrimitives;
-    aPrimitives.push_back(drawinglayer::primitive2d::Primitive2DReference(xBorder.get()));
+    aPrimitives.push_back(drawinglayer::primitive2d::Primitive2DReference(aBorder.get()));
 
     // Process the primitives.
     pProcessor->process(aPrimitives);
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 92044fe33c72..83abdab79b53 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -45,140 +45,56 @@ namespace drawinglayer
 {
     namespace primitive2d
     {
-        BorderLineExtend::BorderLineExtend()
-        :   mfExtends()
-        {
-        }
-
-        BorderLineExtend::BorderLineExtend(
-            double fStart,
-            double fEnd)
-        :   mfExtends(2)
-        {
-            mfExtends[0] = fStart;
-            mfExtends[1] = fEnd;
-        }
-
-        BorderLineExtend::BorderLineExtend(
+        BorderLine::BorderLine(
+            const drawinglayer::attribute::LineAttribute& rLineAttribute,
             double fStartLeft,
             double fStartRight,
             double fEndLeft,
             double fEndRight)
-        :   mfExtends(4)
-        {
-            mfExtends[0] = fStartLeft;
-            mfExtends[1] = fStartRight;
-            mfExtends[2] = fEndLeft;
-            mfExtends[3] = fEndRight;
-        }
-
-        BorderLineExtend::~BorderLineExtend()
-        {
-        }
-
-        bool BorderLineExtend::equalStart() const
+        :   maLineAttribute(rLineAttribute),
+            mfStartLeft(fStartLeft),
+            mfStartRight(fStartRight),
+            mfEndLeft(fEndLeft),
+            mfEndRight(fEndRight),
+            mbIsGap(false)
         {
-            if (mfExtends.empty()|| 2 == mfExtends.size())
-                return true;
-            return mfExtends[0] == mfExtends[1];
         }
 
-        bool BorderLineExtend::equalEnd() const
-        {
-            if (mfExtends.empty() || 2 == mfExtends.size())
-                return true;
-            return mfExtends[2] == mfExtends[3];
-        }
-
-        double BorderLineExtend::getStartLeft() const
-        {
-            if (mfExtends.empty())
-                return 0.0;
-            return mfExtends[0];
-        }
-
-        double BorderLineExtend::getStartRight() const
-        {
-            if (mfExtends.empty())
-                return 0.0;
-            if (2 == mfExtends.size())
-                return mfExtends[0];
-            return mfExtends[1];
-        }
-
-        double BorderLineExtend::getEndLeft() const
+        BorderLine::BorderLine(
+            double fWidth)
+        :   maLineAttribute(basegfx::BColor(), fWidth),
+            mfStartLeft(0.0),
+            mfStartRight(0.0),
+            mfEndLeft(0.0),
+            mfEndRight(0.0),
+            mbIsGap(true)
         {
-            if (mfExtends.empty())
-                return 0.0;
-            if (2 == mfExtends.size())
-                return mfExtends[1];
-            return mfExtends[2];
         }
 
-        double BorderLineExtend::getEndRight() const {
-            if (mfExtends.empty())
-                return 0.0;
-            if (2 == mfExtends.size())
-                return mfExtends[1];
-            return mfExtends[3];
-        }
-
-        double BorderLineExtend::getStartAverage() const
+        BorderLine::~BorderLine()
         {
-            if (mfExtends.empty())
-                return 0.0;
-            if (2 == mfExtends.size())
-                return mfExtends[0];
-            return (mfExtends[0] + mfExtends[1]) * 0.5;
         }
 
-        double BorderLineExtend::getEndAverage() const
+        bool BorderLine::operator==(const BorderLine& rBorderLine) const
         {
-            if (mfExtends.empty())
-                return 0.0;
-            if (2 == mfExtends.size())
-                return mfExtends[1];
-            return (mfExtends[2] + mfExtends[3]) * 0.5;
+            return getLineAttribute() == rBorderLine.getLineAttribute()
+                && getStartLeft() == rBorderLine.getStartLeft()
+                && getStartRight() == rBorderLine.getStartRight()
+                && getEndLeft() == rBorderLine.getEndLeft()
+                && getEndRight() == rBorderLine.getEndRight()
+                && isGap() == rBorderLine.isGap();
         }
 
-        bool BorderLineExtend::operator==(const BorderLineExtend& rBorderLineExtend) const
+        double BorderLine::getAdaptedWidth(double fMinWidth) const
         {
-            if (mfExtends.size() == rBorderLineExtend.mfExtends.size())
+            if(isGap())
             {
-                return mfExtends == rBorderLineExtend.mfExtends;
+                return std::max(getLineAttribute().getWidth(), fMinWidth);
+            }
+            else
+            {
+                return getLineAttribute().getWidth();
             }
-
-            return false;
-        }
-
-        BorderLine::BorderLine(
-            double fWidth,
-            const basegfx::BColor& rRGBColor,
-            const BorderLineExtend& rBorderLineExtend)
-            : mfWidth(fWidth),
-            maRGBColor(rRGBColor),
-            maBorderLineExtend(rBorderLineExtend)
-        {
-        }
-
-        BorderLine::BorderLine(
-            double fWidth,
-            const basegfx::BColor& rRGBColor)
-            : mfWidth(fWidth),
-            maRGBColor(rRGBColor),
-            maBorderLineExtend()
-        {
-        }
-
-        BorderLine::~BorderLine()
-        {
-        }
-
-        bool BorderLine::operator==(const BorderLine& rBorderLine) const
-        {
-            return getWidth() == rBorderLine.getWidth()
-                && getRGBColor() == rBorderLine.getRGBColor()
-                && getBorderLineExtend() == rBorderLine.getBorderLineExtend();
         }
 
         // helper to add a centered, maybe stroked line primitive to rContainer
@@ -187,7 +103,7 @@ namespace drawinglayer
             const basegfx::B2DPoint& rStart,
             const basegfx::B2DPoint& rEnd,
             const attribute::LineAttribute& rLineAttribute,
-            const attribute::StrokeAttribute & rStrokeAttribute)
+            const attribute::StrokeAttribute& rStrokeAttribute)
         {
             basegfx::B2DPolygon aPolygon;
 
@@ -211,98 +127,139 @@ namespace drawinglayer
             }
         }
 
+        double BorderLinePrimitive2D::getFullWidth() const
+        {
+            double fRetval(0.0);
+
+            for(const auto& candidate : maBorderLines)
+            {
+                fRetval += candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance);
+            }
+
+            return fRetval;
+        }
+
         Primitive2DContainer BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
         {
             Primitive2DContainer aContainer;
 
-            if (!getStart().equal(getEnd()))
+            if (!getStart().equal(getEnd()) && !getBorderLines().empty())
             {
                 // get data and vectors
                 basegfx::B2DVector aVector(getEnd() - getStart());
                 aVector.normalize();
                 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
-                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);
+                const double fFullWidth(getFullWidth());
+                double fOffset(fFullWidth * -0.5);
 
-                if (3 == getBorderLines().size())
+                for(const auto& candidate : maBorderLines)
                 {
-                    // double line with gap. Use mfDiscreteGapDistance (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]);

... etc. - the rest is truncated


More information about the Libreoffice-commits mailing list