borderline: merge redefined, mirrored Styles

Redefined merge of BorderlinePrimitives, removed old Writer
stuff for it. Also added support for handling Styles mirrored
for extension calculations.
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 9421ed8..5fc3b57 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -144,7 +144,7 @@ namespace drawinglayer

                for(const auto& candidate : maBorderLines)
                {
                    const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance) * 0.5);
                    const double fWidth(candidate.getAdaptedWidth(mfSmallestAllowedDiscreteGapDistance));

                    if(!candidate.isGap())
                    {
@@ -369,6 +369,116 @@ namespace drawinglayer
        // provide unique ID
        ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)

        Primitive2DReference tryMergeBorderLinePrimitive2D(
            const Primitive2DReference& rCandidateA,
            const Primitive2DReference& rCandidateB)
        {
            // try to cast to BorderLinePrimitive2D
            const primitive2d::BorderLinePrimitive2D* pCandidateA = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateA.get());
            const primitive2d::BorderLinePrimitive2D* pCandidateB = dynamic_cast< const primitive2d::BorderLinePrimitive2D* >(rCandidateB.get());

            // we need a comparable BorderLinePrimitive2D
            if(nullptr == pCandidateA || nullptr == pCandidateB)
            {
                return Primitive2DReference();
            }

            // start of candidate has to match end of this
            if(!pCandidateA->getEnd().equal(pCandidateB->getStart()))
            {
                return Primitive2DReference();
            }

            // candidate A needs a length
            if(pCandidateA->getStart().equal(pCandidateA->getEnd()))
            {
                return Primitive2DReference();
            }

            // candidate B needs a length
            if(pCandidateB->getStart().equal(pCandidateB->getEnd()))
            {
                return Primitive2DReference();
            }

            // StrokeAttribute has to be equal
            if(!(pCandidateA->getStrokeAttribute() == pCandidateB->getStrokeAttribute()))
            {
                return Primitive2DReference();
            }

            // direction has to be equal -> cross product == 0.0
            const basegfx::B2DVector aVT(pCandidateA->getEnd() - pCandidateA->getStart());
            const basegfx::B2DVector aVC(pCandidateB->getEnd() - pCandidateB->getStart());
            if(!rtl::math::approxEqual(0.0, aVC.cross(aVT)))
            {
                return Primitive2DReference();
            }

            // number BorderLines has to be equal
            const size_t count(pCandidateA->getBorderLines().size());
            if(count != pCandidateB->getBorderLines().size())
            {
                return Primitive2DReference();
            }

            for(size_t a(0); a < count; a++)
            {
                const BorderLine& rBT(pCandidateA->getBorderLines()[a]);
                const BorderLine& rBC(pCandidateB->getBorderLines()[a]);

                // LineAttribute has to be the same
                if(!(rBC.getLineAttribute() == rBT.getLineAttribute()))
                {
                    return Primitive2DReference();
                }

                // isGap has to be the same
                if(rBC.isGap() != rBT.isGap())
                {
                    return Primitive2DReference();
                }

                if(!rBT.isGap())
                {
                    // when not gap, the line extends have at least reach to the center ( > 0.0),
                    // else there is a extend usage. When > 0.0 they just overlap, no problem
                    if(rBT.getEndLeft() >= 0.0
                        && rBT.getEndRight() >= 0.0
                        && rBC.getStartLeft() >= 0.0
                        && rBC.getStartRight() >= 0.0)
                    {
                        // okay
                    }
                    else
                    {
                        return Primitive2DReference();
                    }
                }
            }

            // all conditions met, create merged primitive
            std::vector< BorderLine > aMergedBorderLines;

            for(size_t a(0); a < count; a++)
            {
                const BorderLine& rBT(pCandidateA->getBorderLines()[a]);
                const BorderLine& rBC(pCandidateB->getBorderLines()[a]);

                aMergedBorderLines.push_back(
                    BorderLine(
                        rBT.getLineAttribute(),
                        rBT.getStartLeft(), rBT.getStartRight(),
                        rBC.getEndLeft(), rBC.getEndRight()));
            }

            return Primitive2DReference(
                new BorderLinePrimitive2D(
                    pCandidateA->getStart(),
                    pCandidateB->getEnd(),
                    aMergedBorderLines,
                    pCandidateA->getStrokeAttribute()));
        }
    } // end of namespace primitive2d
} // end of namespace drawinglayer

diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
index 992347c..b6634f6 100644
--- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
@@ -87,6 +87,13 @@ namespace drawinglayer
            bool operator==(const BorderLine& rBorderLine) const;
        };

        /// helper to try to merge two instances of BorderLinePrimitive2D. If it was possible,
        /// a merged version is in the returned Primitive2DReference. Lots of preconditions
        /// have to be met to allow that, see implementation (and maybe even expand)
        Primitive2DReference DRAWINGLAYER_DLLPUBLIC tryMergeBorderLinePrimitive2D(
            const Primitive2DReference& rCandidateA,
            const Primitive2DReference& rCandidateB);

        /** BorderLinePrimitive2D class

        This is the basic primitive to build frames around objects, e.g. tables.
diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx
index 9ebb4c8..1b130ef 100644
--- a/include/svx/framelink.hxx
+++ b/include/svx/framelink.hxx
@@ -213,66 +213,27 @@ public:

inline bool operator>( const Style& rL, const Style& rR ) { return rR.operator<(rL); }

// Various helper functions

/** Checks whether two horizontal frame borders are "connectable".

    Two borders are "connectable" in terms of this function, if both can be
    drawn with only one call of a border drawing function. This means, the two
    frame borders must have equal style and color, and none of the other
    vertical and diagonal frame borders break the lines of the two borders in
    any way (i.e. two vertical double frame borders would break the horizonal
    frame borders). Of course this function can be used for vertical frame
    borders as well.

    The following picture shows the meaning of all passed parameters:

                      \      rTFromT      /
                        \       |       /
                   rTFromTL     |   rTFromTR
                            \   |   /
                              \ | /
    ======== rLBorder =========   ========== rRBorder =======
                              / | \
                            /   |   \
                   rBFromBL     |   rBFromBR
                        /       |       \
                      /      rBFromB      \

    @return
        True, if rLBorder and rRBorder can be drawn in one step without
        interruption at their connection point.
 */
SVX_DLLPUBLIC bool CheckFrameBorderConnectable(
    const Style&        rLBorder,       /// Style of the left frame border to connect.
    const Style&        rRBorder,       /// Style of the right frame border to connect.

    const Style&        rTFromTL,       /// Diagonal frame border from top-left to connection point.
    const Style&        rTFromT,        /// Vertical frame border from top to connection point.
    const Style&        rTFromTR,       /// Horizontal frame border from top-right to connection point.

    const Style&        rBFromBL,       /// Diagonal frame border from bottom-left to connection point.
    const Style&        rBFromB,        /// Vertical frame border from bottom to connection point.
    const Style&        rBFromBR        /// Horizontal frame border from bottom-right to connection point.
);


// Drawing functions

class SAL_WARN_UNUSED SVX_DLLPUBLIC StyleVectorCombination
{
private:
    const Style&                mrStyle;
    const basegfx::B2DVector&   mrB2DVector;
    const basegfx::B2DVector    maB2DVector;
    const bool                  mbMirrored;


public:
    StyleVectorCombination(const Style& rStyle, const basegfx::B2DVector& rB2DVector) :
    StyleVectorCombination(const Style& rStyle, const basegfx::B2DVector& rB2DVector, bool bMirrored) :
        mrStyle(rStyle),
        mrB2DVector(rB2DVector)
    {}
        maB2DVector(rB2DVector),
        mbMirrored(bMirrored)
    {
    }

    const Style& getStyle() const { return mrStyle; }
    const basegfx::B2DVector& getB2DVector() const { return mrB2DVector; }
    const basegfx::B2DVector& getB2DVector() const { return maB2DVector; }
    bool isMirrored() const { return mbMirrored; }
};

typedef std::vector< StyleVectorCombination > StyleVectorTable;
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index ca66b28..c7a6377 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 (RefMode::Centered != rStyle.GetRefMode())
        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 != aRefMode)
        {
            const double fHalfWidth(rStyle.GetWidth() * 0.5);

            if (RefMode::Begin == rStyle.GetRefMode())
            if (RefMode::Begin == aRefMode)
            {
                // move aligned below vector
                fRefModeOffset = fHalfWidth;
            }
            else if (RefMode::End == rStyle.GetRefMode())
            else if (RefMode::End == aRefMode)
            {
                // move aligned above vector
                fRefModeOffset = -fHalfWidth;
            }
        }

        if (rStyle.Dist() && rStyle.Secn())
        if (rStyle.Dist() && fSecn)
        {
            // both or all three lines used
            const bool bPrimTransparent(0xff == rStyle.GetColorPrim().GetTransparency());
            const bool bDistTransparent(!rStyle.UseGapColor() || 0xff == rStyle.GetColorGap().GetTransparency());
            const bool bSecnTransparent(0xff == rStyle.GetColorSecn().GetTransparency());
            const bool bSecnTransparent(0xff == aSecn.GetTransparency());

            if(!bPrimTransparent || !bDistTransparent || !bSecnTransparent)
            {
                const double a(fRefModeOffset - (rStyle.GetWidth() * 0.5));
                const double b(a + rStyle.Prim());
                const double b(a + fPrim);
                const double c(b + rStyle.Dist());
                const double d(c + rStyle.Secn());
                const double d(c + fSecn);

                offsets.push_back(
                    OffsetAndHalfWidthAndColor(
                        (a + b) * 0.5,
                        rStyle.Prim() * 0.5,
                        nullptr != pForceColor ? *pForceColor : rStyle.GetColorPrim()));
                        fPrim * 0.5,
                        nullptr != pForceColor ? *pForceColor : aPrim));

                offsets.push_back(
                    OffsetAndHalfWidthAndColor(
@@ -441,8 +440,8 @@ void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pF
                offsets.push_back(
                    OffsetAndHalfWidthAndColor(
                        (c + d) * 0.5,
                        rStyle.Secn() * 0.5,
                        nullptr != pForceColor ? *pForceColor : rStyle.GetColorSecn()));
                        fSecn * 0.5,
                        nullptr != pForceColor ? *pForceColor : aSecn));
            }
        }
        else
@@ -453,11 +452,13 @@ void getOffsetAndHalfWidthAndColorFromStyle(const Style& rStyle, const Color* pF
                offsets.push_back(
                    OffsetAndHalfWidthAndColor(
                        fRefModeOffset,
                        rStyle.Prim() * 0.5,
                        nullptr != pForceColor ? *pForceColor : rStyle.GetColorPrim()));
                        fPrim * 0.5,
                        nullptr != pForceColor ? *pForceColor : aPrim));
            }
        }
    }

    return fRefModeOffset;
}

void getCutSet(
@@ -525,7 +526,7 @@ void getExtends(
            for(const auto& rStyleVectorCombination : rStyleVectorTable)
            {
                std::vector< OffsetAndHalfWidthAndColor > otherOffsets;
                getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, otherOffsets);
                getOffsetAndHalfWidthAndColorFromStyle(rStyleVectorCombination.getStyle(), nullptr, rStyleVectorCombination.isMirrored(), otherOffsets);

                if(!otherOffsets.empty())
                {
@@ -568,7 +569,7 @@ void CreateBorderPrimitives(
{
    // get offset color pairs for  style, one per visible line
    std::vector< OffsetAndHalfWidthAndColor > myOffsets;
    getOffsetAndHalfWidthAndColorFromStyle(rBorder, pForceColor, myOffsets);
    const double fRefModeOffset(getOffsetAndHalfWidthAndColorFromStyle(rBorder, pForceColor, false, myOffsets));
    const size_t nOffsets(myOffsets.size());

    if(nOffsets)
@@ -624,12 +625,13 @@ void CreateBorderPrimitives(
        static double fPatScFact(10.0); // 10.0 multiply, see old code
        const std::vector<double> aDashing(svtools::GetLineDashing(rBorder.Type(), rBorder.PatternScale() * fPatScFact));
        const drawinglayer::attribute::StrokeAttribute aStrokeAttribute(aDashing);
        const basegfx::B2DPoint aStart(rOrigin + (aPerpendX * fRefModeOffset));

        rTarget.append(
            drawinglayer::primitive2d::Primitive2DReference(
                new drawinglayer::primitive2d::BorderLinePrimitive2D(
                    rOrigin,
                    rOrigin + rX,
                    aStart,
                    aStart + rX,
                    aBorderlines,
                    aStrokeAttribute)));
    }
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index 6052c23..2d81cae 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -954,11 +954,11 @@ void HelperCreateHorizontalEntry(
    const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
    StyleVectorTable aStart;

    if(rStartFromTR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromTR, rX - rY));
    if(rStartLFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromT, -rY));
    if(rStartLFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromL, -rX));
    if(rStartLFromB.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromB, rY));
    if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY));
    if(rStartFromTR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromTR, rX - rY, false));
    if(rStartLFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromT, -rY, true));
    if(rStartLFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromL, -rX, true));
    if(rStartLFromB.IsUsed()) aStart.push_back(StyleVectorCombination(rStartLFromB, rY, false));
    if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false));

    // get involved styles at end
    const Style& rEndFromTL(rArray.GetCellStyleBR( col, row - 1 ));
@@ -968,11 +968,11 @@ void HelperCreateHorizontalEntry(
    const Style& rEndFromBL(rArray.GetCellStyleTR( col, row ));
    StyleVectorTable aEnd;

    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX -rY));
    if(rEndRFromT.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromT, -rY));
    if(rEndRFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromR, rX));
    if(rEndRFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromB, rY));
    if(rEndFromBL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromBL, rY - rX));
    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, -rX -rY, true));
    if(rEndRFromT.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromT, -rY, true));
    if(rEndRFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromR, rX, false));
    if(rEndRFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndRFromB, rY, false));
    if(rEndFromBL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromBL, rY - rX, true));

    CreateBorderPrimitives(
        rSequence,
@@ -999,11 +999,11 @@ void HelperCreateVerticalEntry(
    const Style& rStartFromBR(rArray.GetCellStyleTL( col, row ));
    StyleVectorTable aStart;

    if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY));
    if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX));
    if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY));
    if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX));
    if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX));
    if(rStartFromBR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBR, rX + rY, false));
    if(rStartTFromR.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromR, rX, false));
    if(rStartTFromT.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromT, rY, true));
    if(rStartTFromL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartTFromL, -rX, true));
    if(rStartFromBL.IsUsed()) aStart.push_back(StyleVectorCombination(rStartFromBL, rY - rX, true));

    // get involved styles at end
    const Style& rEndFromTL(rArray.GetCellStyleBR( col - 1, row ));
@@ -1013,11 +1013,11 @@ void HelperCreateVerticalEntry(
    const Style& rEndFromTR(rArray.GetCellStyleBL( col, row ));
    StyleVectorTable aEnd;

    if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY));
    if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX));
    if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY));
    if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX));
    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY));
    if(rEndFromTR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTR, rX - rY, false));
    if(rEndBFromR.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromR, rX, false));
    if(rEndBFromB.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromB, -rY, false));
    if(rEndBFromL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndBFromL, rX, true));
    if(rEndFromTL.IsUsed()) aEnd.push_back(StyleVectorCombination(rEndFromTL, rX + rY, true));

    CreateBorderPrimitives(
        rSequence,
@@ -1069,6 +1069,48 @@ void HelperCreateEntry(const Array& rArray, const Style& rStyle, drawinglayer::p
    }
}

void HelperMergeInB2DPrimitiveArray(
    const drawinglayer::primitive2d::Primitive2DContainer& rSource,
    drawinglayer::primitive2d::Primitive2DContainer& rTarget)
{
    if(rSource.size() > 1)
    {
        drawinglayer::primitive2d::Primitive2DReference aCandidate;

        for(const auto& a : rSource)
        {
            if(aCandidate.is())
            {
                const drawinglayer::primitive2d::Primitive2DReference aMerge(
                    drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(aCandidate, a));

                if(aMerge.is())
                {
                    aCandidate = aMerge;
                }
                else
                {
                    rTarget.append(aCandidate);
                    aCandidate = a;
                }
            }
            else
            {
                aCandidate = a;
            }
        }

        if(aCandidate.is())
        {
            rTarget.append(aCandidate);
        }
    }
    else
    {
        rTarget.append(rSource);
    }
}

drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
    size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow,
    const Color* pForceColor ) const
@@ -1078,7 +1120,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(

    // various primitive sequences to collect the different border types
    drawinglayer::primitive2d::Primitive2DContainer aHorizontalSequence;
    drawinglayer::primitive2d::Primitive2DContainer aVerticalSequence;
    std::vector< drawinglayer::primitive2d::Primitive2DContainer > aVerticalSequences(nLastCol - nFirstCol + 1);
    drawinglayer::primitive2d::Primitive2DContainer aCrossSequence;

    for (size_t nRow = nFirstRow; nRow <= nLastRow; ++nRow)
@@ -1131,7 +1173,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(

                    if(rLeft.IsUsed())
                    {
                        HelperCreateEntry(*this, rLeft, aVerticalSequence, pForceColor);
                        HelperCreateEntry(*this, rLeft, aVerticalSequences[nCol - nFirstCol], pForceColor);
                    }
                }

@@ -1141,7 +1183,7 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(

                    if(rRight.IsUsed())
                    {
                        HelperCreateEntry(*this, rRight, aVerticalSequence, pForceColor);
                        HelperCreateEntry(*this, rRight, aVerticalSequences[nCol - nFirstCol], pForceColor);
                    }
                }

@@ -1156,15 +1198,15 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(

                        /// Fill top-left Style Table
                        const Style& rTLFromRight(GetCellStyleTop(_nFirstCol, _nFirstRow));
                        if(rTLFromRight.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromRight, aX));
                        if(rTLFromRight.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromRight, aX, false));
                        const Style& rTLFromBottom(GetCellStyleLeft(_nFirstCol, _nFirstRow));
                        if(rTLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromBottom, aY));
                        if(rTLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rTLFromBottom, aY, false));

                        /// Fill bottom-right Style Table
                        const Style& rBRFromBottom(GetCellStyleRight(_nLastCol, _nLastRow));
                        if(rBRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromBottom, -aY));
                        if(rBRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromBottom, -aY, true));
                        const Style& rBRFromLeft(GetCellStyleBottom(_nLastCol, _nLastRow));
                        if(rBRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromLeft, -aX));
                        if(rBRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rBRFromLeft, -aX, true));

                        CreateBorderPrimitives(
                            aCrossSequence,
@@ -1186,15 +1228,15 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(

                        /// Fill bottom-left Style Table
                        const Style& rBLFromTop(GetCellStyleLeft(_nFirstCol, _nLastRow));
                        if(rBLFromTop.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromTop, -aY));
                        if(rBLFromTop.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromTop, -aY, true));
                        const Style& rBLFromBottom(GetCellStyleBottom(_nFirstCol, _nLastRow));
                        if(rBLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromBottom, aX));
                        if(rBLFromBottom.IsUsed()) aStart.push_back(StyleVectorCombination(rBLFromBottom, aX, false));

                        /// Fill top-right Style Table
                        const Style& rTRFromBottom(GetCellStyleRight(_nLastCol, _nFirstRow));
                        if(rTRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromBottom, -aY));
                        if(rTRFromBottom.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromBottom, -aY, true));
                        const Style& rTRFromLeft(GetCellStyleTop(_nLastCol, _nFirstRow));
                        if(rTRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromLeft, -aX));
                        if(rTRFromLeft.IsUsed()) aEnd.push_back(StyleVectorCombination(rTRFromLeft, -aX, false));

                        CreateBorderPrimitives(
                            aCrossSequence,
@@ -1211,9 +1253,13 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
        }
    }

    // to stay compatible, create order as it was formally
    aCrossSequence.append(aHorizontalSequence);
    aCrossSequence.append(aVerticalSequence);
    // to stay compatible, create order as it was formally. Also try to
    // merge primitives as far as possible
    HelperMergeInB2DPrimitiveArray(aHorizontalSequence, aCrossSequence);
    for(const auto& aVert : aVerticalSequences)
    {
        HelperMergeInB2DPrimitiveArray(aVert, aCrossSequence);
    }

    return aCrossSequence;
}
diff --git a/svx/source/table/viewcontactoftableobj.cxx b/svx/source/table/viewcontactoftableobj.cxx
index d696569..52d6ce4 100644
--- a/svx/source/table/viewcontactoftableobj.cxx
+++ b/svx/source/table/viewcontactoftableobj.cxx
@@ -197,7 +197,7 @@ namespace sdr
            return svx::frame::Style();
        }

        void createForVector(drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX,
        void createForVector(bool bHor, drawinglayer::primitive2d::Primitive2DContainer& rContainer, const basegfx::B2DPoint& rOrigin, const basegfx::B2DVector& rX,
            const svx::frame::Style& rLine,
            const svx::frame::Style& rLeftA, const svx::frame::Style& rLeftB, const svx::frame::Style& rLeftC,
            const svx::frame::Style& rRightA, const svx::frame::Style& rRightB, const svx::frame::Style& rRightC)
@@ -206,17 +206,16 @@ namespace sdr
            svx::frame::StyleVectorTable aStart;
            svx::frame::StyleVectorTable aEnd;
            const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(rX));
            const double fTwipsToMM(127.0 / 72.0);

            /// Fill top-left Style Table
            if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY));
            if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX));
            if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY));
            if(rLeftA.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftA, -aY, bHor ? true : false));
            if(rLeftB.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftB, -rX, bHor ? true : true));
            if(rLeftC.IsUsed()) aStart.push_back(svx::frame::StyleVectorCombination(rLeftC, aY, bHor ? false : true));

            /// Fill bottom-right Style Table
            if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY));
            if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX));
            if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY));
            if(rRightA.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightA, -aY, bHor ? true : false));
            if(rRightB.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightB, rX, bHor ? false : false));
            if(rRightC.IsUsed()) aEnd.push_back(svx::frame::StyleVectorCombination(rRightC, aY, bHor ? false : true));

            CreateBorderPrimitives(
                rContainer,
@@ -350,32 +349,31 @@ namespace sdr
                                        const basegfx::B2DPoint aOrigin(aCellMatrix * basegfx::B2DPoint(0.0, 0.0));
                                        const basegfx::B2DVector aX(aCellMatrix * basegfx::B2DVector(1.0, 0.0));
                                        const basegfx::B2DVector aY(aCellMatrix * basegfx::B2DVector(0.0, 1.0));
                                        const double fTwipsToMM(127.0 / 72.0);

                                        if(aLeftLine.IsUsed())
                                        {
                                            createForVector(aBorderSequence, aOrigin, aY, aLeftLine,
                                            createForVector(false, aBorderSequence, aOrigin, aY, aLeftLine,
                                                aTopLine, aLeftFromTLine, aTopFromLLine,
                                                aBottomLine, aLeftFromBLine, aBottomFromLLine);
                                        }

                                        if(aBottomLine.IsUsed())
                                        {
                                            createForVector(aBorderSequence, aOrigin + aY, aX, aBottomLine,
                                            createForVector(true, aBorderSequence, aOrigin + aY, aX, aBottomLine,
                                                aLeftLine, aBottomFromLLine, aLeftFromBLine,
                                                aRightLine, aBottomFromRLine, aRightFromBLine);
                                        }

                                        if(aRightLine.IsUsed())
                                        {
                                            createForVector(aBorderSequence, aOrigin + aX, aY, aRightLine,
                                            createForVector(false, aBorderSequence, aOrigin + aX, aY, aRightLine,
                                                aTopFromRLine, aRightFromTLine, aTopLine,
                                                aBottomFromRLine, aRightFromBLine, aBottomLine);
                                        }

                                        if(aTopLine.IsUsed())
                                        {
                                            createForVector(aBorderSequence, aOrigin, aX, aTopLine,
                                            createForVector(true, aBorderSequence, aOrigin, aX, aTopLine,
                                                aLeftFromTLine, aTopFromLLine, aLeftLine,
                                                aRightFromTLine, aTopFromRLine, aRightLine);
                                        }
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index ac2d3ba..4ba2fc1 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -221,7 +221,7 @@ class BorderLines
{
    drawinglayer::primitive2d::Primitive2DContainer m_Lines;
public:
    void AddBorderLine(css::uno::Reference<BorderLinePrimitive2D> const& xLine, SwPaintProperties const & properties);
    void AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine);
    drawinglayer::primitive2d::Primitive2DContainer GetBorderLines_Clear()
    {
        drawinglayer::primitive2d::Primitive2DContainer lines;
@@ -472,197 +472,20 @@ SwSavePaintStatics::~SwSavePaintStatics()
    gProp.aSScaleY            = aSScaleY;
}

/**
 * Check whether the two primitive can be merged
 *
 * @param[in]   mergeA  A primitive start and end position
 * @param[in]   mergeB  B primitive start and end position
 * @return      1       if A and B can be merged to a primite staring with A, ending with B
 *              2       if A and B can be merged to a primite staring with B, ending with A
 *              0       if A and B can't be merged
**/
static sal_uInt8 lcl_TryMergeLines(
    pair<double, double> const& mergeA,
    pair<double, double> const& mergeB,
    SwPaintProperties const & properties)
void BorderLines::AddBorderLine(const drawinglayer::primitive2d::Primitive2DReference& rLine)
{
    double const fMergeGap(properties.nSPixelSzW + properties.nSHalfPixelSzW); // NOT static!
    // A is above/before B
    if( mergeA.second <= mergeB.first &&
        mergeA.second + fMergeGap >= mergeB.first )
    for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend(); ++it)
    {
        return 1;
    }
    // B is above/before A
    else if( mergeB.second <= mergeA.first &&
             mergeB.second + fMergeGap >= mergeA.first )
    {
        return 2;
    }
    return 0;
}
        const drawinglayer::primitive2d::Primitive2DReference aMerged(drawinglayer::primitive2d::tryMergeBorderLinePrimitive2D(*it, rLine));

/**
 * Make a new primitive from the two input borderline primitive
 *
 * @param[in]   rLine       starting primitive
 * @param[in]   rOther      ending primitive
 * @param[in]   rStart      starting point of merged primitive
 * @param[in]   rEnd        ending point of merged primitive
 * @return      merged primitive
**/
static rtl::Reference<BorderLinePrimitive2D>
lcl_MergeBorderLines(
    BorderLinePrimitive2D const& rLine,
    BorderLinePrimitive2D const& rOther,
    basegfx::B2DPoint const& rStart,
    basegfx::B2DPoint const& rEnd)
{
    const std::vector< BorderLine >& rLineLeft(rLine.getBorderLines());
    const std::vector< BorderLine >& rOtherLeft(rOther.getBorderLines());
    const size_t aSize(std::min(rLineLeft.size(), rOtherLeft.size()));
    std::vector< BorderLine > aNew;

    for(size_t a(0); a < aSize; a++)
    {
        const BorderLine& la(rLineLeft[a]);
        const BorderLine& lb(rOtherLeft[a]);

        if(la.isGap() || lb.isGap())
        if (aMerged.is())
        {
            aNew.push_back(la);
        }
        else
        {
            aNew.push_back(
                BorderLine(
                    la.getLineAttribute(),
                    la.getStartLeft(),
                    la.getStartRight(),
                    lb.getEndLeft(),
                    lb.getEndRight()));
        }
    }

    return new BorderLinePrimitive2D(
        rStart,
        rEnd,
        aNew,
        rLine.getStrokeAttribute());
}

/**
 * Merge the two borderline if possible.
 *
 * @param[in]   rThis   one borderline primitive
 * @param[in]   rOther  other borderline primitive
 * @return      merged borderline including the two input primitive, if they can be merged
 *              0, otherwise
**/
static rtl::Reference<BorderLinePrimitive2D>
lcl_TryMergeBorderLine(BorderLinePrimitive2D const& rThis,
                       BorderLinePrimitive2D const& rOther,
                       SwPaintProperties const & properties)
{
    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)
    {
        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);
            }
        }

        // The merged primitive starts with rThis and ends with rOther
        if (nRet == 1)
        {
            basegfx::B2DPoint const start(
                rThis.getStart().getX(), rThis.getStart().getY());
            basegfx::B2DPoint const end(
                rOther.getEnd().getX(), rOther.getEnd().getY());
            return lcl_MergeBorderLines(rThis, rOther, start, end).get();
        }
        // The merged primitive starts with rOther and ends with rThis
        else if(nRet == 2)
        {
            basegfx::B2DPoint const start(
                rOther.getStart().getX(), rOther.getStart().getY());
            basegfx::B2DPoint const end(
                rThis.getEnd().getX(), rThis.getEnd().getY());
            return lcl_MergeBorderLines(rOther, rThis, start, end).get();
        }
    }
    return nullptr;
}

void BorderLines::AddBorderLine(
        css::uno::Reference<BorderLinePrimitive2D> const& xLine, SwPaintProperties const & properties)
{
    for (drawinglayer::primitive2d::Primitive2DContainer::reverse_iterator it = m_Lines.rbegin(); it != m_Lines.rend();
         ++it)
    {
        rtl::Reference<BorderLinePrimitive2D> const xMerged(
            lcl_TryMergeBorderLine(*static_cast<BorderLinePrimitive2D*>((*it).get()), *xLine.get(), properties).get());
        if (xMerged.is())
        {
            *it = xMerged.get(); // replace existing line with merged
            *it = aMerged; // replace existing line with merged // lcl_TryMergeBorderLine
            return;
        }
    }
    m_Lines.push_back(xLine);

    m_Lines.append(rLine);
}

SwLineRect::SwLineRect( const SwRect &rRect, const Color *pCol, const SvxBorderLineStyle nStyl,
@@ -2608,6 +2431,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
    aUpper.Pos() += pUpper->Frame().Pos();
    SwRect aUpperAligned( aUpper );
    ::SwAlignRect( aUpperAligned, gProp.pSGlobalShell, &rDev );
    drawinglayer::primitive2d::Primitive2DContainer aSequence;

    while ( true )
    {
@@ -2715,8 +2539,6 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons

            if(aStyles[0].IsUsed())
            {
                drawinglayer::primitive2d::Primitive2DContainer aSequence;

                if (bHori)
                {
                    const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
@@ -2728,13 +2550,13 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                        svx::frame::StyleVectorTable aStartTable;
                        svx::frame::StyleVectorTable aEndTable;

                        if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], -aY)); // aLFromT
                        if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX)); // aLFromL
                        if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], aY)); // aLFromB
                        if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], -aY, true)); // aLFromT
                        if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX, true)); // aLFromL
                        if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], aY, false)); // aLFromB

                        if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], -aY)); // aRFromT
                        if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX)); // aRFromR
                        if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], aY)); // aRFromB
                        if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], -aY, true)); // aRFromT
                        if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX, false)); // aRFromR
                        if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], aY, false)); // aRFromB

                        CreateBorderPrimitives(
                            aSequence,
@@ -2743,7 +2565,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                            aStyles[ 0 ],
                            aStartTable,
                            aEndTable,
                            nullptr
                            pTmpColor
                        );
                    }
                }
@@ -2758,13 +2580,13 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                        svx::frame::StyleVectorTable aStartTable;
                        svx::frame::StyleVectorTable aEndTable;

                        if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], -aY)); // aTFromR
                        if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX)); // aTFromT
                        if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], aY)); // aTFromL
                        if(aStyles[ 3 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 3 ], -aY, false)); // aTFromR
                        if(aStyles[ 2 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 2 ], -aX, true)); // aTFromT
                        if(aStyles[ 1 ].IsUsed()) aStartTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 1 ], aY, true)); // aTFromL

                        if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], -aY)); // aBFromR
                        if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX)); // aBFromB
                        if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], aY)); // aBFromL
                        if(aStyles[ 6 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 6 ], -aY, false)); // aBFromR
                        if(aStyles[ 5 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 5 ], aX, false)); // aBFromB
                        if(aStyles[ 4 ].IsUsed()) aEndTable.push_back(svx::frame::StyleVectorCombination(aStyles[ 4 ], aY, true)); // aBFromL

                        CreateBorderPrimitives(
                            aSequence,
@@ -2773,18 +2595,17 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                            aStyles[ 0 ],
                            aStartTable,
                            aEndTable,
                            nullptr
                            pTmpColor
                        );
                    }
                }

                mrTabFrame.ProcessPrimitives(aSequence);
            }
        }

        ++aIter;
    }

    mrTabFrame.ProcessPrimitives(aSequence);

    // restore output device:
    rDev.SetDrawMode( nOldDrawMode );
}
@@ -4839,7 +4660,7 @@ static void lcl_MakeBorderLine(SwRect const& rRect,
    // When rendering to very small (virtual) devices, like when producing
    // page thumbnails in a mobile device app, the line geometry can end up
    // bogus (negative width or height), so just ignore such border lines.
    // Otherwise we will run into assertions later in lcl_TryMergeBorderLine()
    // Otherwise we will run into assertions later in BorderLinePrimitive2D::tryMerge()
    // at least.
    if (aEnd.getX() < aStart.getX() ||
        aEnd.getY() < aStart.getY())
@@ -4894,14 +4715,14 @@ static void lcl_MakeBorderLine(SwRect const& rRect,
                nExtentRightEnd));
    }

    rtl::Reference<BorderLinePrimitive2D> xLine(
    drawinglayer::primitive2d::Primitive2DReference aLine(
        new BorderLinePrimitive2D(
            aStart,
            aEnd,
            aBorderlines,
            aStrokeAttribute));

    properties.pBLines->AddBorderLine(xLine.get(), properties);
    properties.pBLines->AddBorderLine(aLine);
}

/**