[Libreoffice-commits] core.git: Branch 'private/swe/libreoffice-5-2+backports' - drawinglayer/Library_drawinglayer.mk drawinglayer/qa drawinglayer/source include/drawinglayer include/svx sc/source svx/source sw/source

Armin Le Grand Armin.Le.Grand at cib.de
Wed Aug 16 10:20:56 UTC 2017


 drawinglayer/Library_drawinglayer.mk                              |    1 
 drawinglayer/qa/unit/border.cxx                                   |   59 -
 drawinglayer/source/primitive2d/borderlineprimitive2d.cxx         |  399 +++-------
 drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx  |   64 -
 drawinglayer/source/processor2d/vclpixelprocessor2d.cxx           |  390 ---------
 drawinglayer/source/processor2d/vclpixelprocessor2d.hxx           |    1 
 include/drawinglayer/primitive2d/borderlineprimitive2d.hxx        |   33 
 include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx |   65 -
 include/svx/framelink.hxx                                         |    8 
 include/svx/framelinkarray.hxx                                    |    7 
 sc/source/ui/view/output.cxx                                      |   86 +-
 svx/source/dialog/framelink.cxx                                   |  103 +-
 svx/source/dialog/framelinkarray.cxx                              |  165 +++-
 svx/source/dialog/frmsel.cxx                                      |   32 
 sw/source/core/layout/paintfrm.cxx                                |   52 -
 15 files changed, 506 insertions(+), 959 deletions(-)

New commits:
commit 3e70aa53522ffe3ffaf0e49e9ca0d21540a9f9d4
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Tue Jul 4 16:28:58 2017 +0200

    borderline: correct problems with border display
    
    Borderline display with direct paint and with primitive direct
    paint has quite some errors in the current state. Started to
    unify usages, check deeper with creation/usage.
    
    borderline: deep changes to BorderLine
    
    Found basic error in determining the offset values
    for BorderLinePrimitive creation, these were not
    centered on the lines. Corrected that. This makes
    it possible to remove the formally used clipping
    which seems to have been used to correct that. Also
    allows to go back to a 'normal' decomposition that
    creates line primitives as expected. That again can
    then be painted quite normally.
    Also added view-dependent case to the decomposition
    to guarantee a gap of one discrete unit (pixel).
    Removed the direct painter, too. Checked and corrected
    stroking.
    
    borderline: Adapted previews to primitives
    
    Added code to use the primitive representation in
    all dialogs and apps using tables. The edit views
    use these mostly, so the preview should do that,
    too. Currently missing is a good visualization of
    diagonals, but this is also true for edit views.
    Checked all apps and table usages to not get worse
    
    borderline: correct line dash visualization
    
    When a dashed line is used, a factor of 10.0 was applied in the
    original coded, added that. Also the orientation of vertical
    borders was inverted since it was simpler to exchange Start/End,
    but this also mirrors the line dash visualisation, corrected that
    
    e95e246d5563360617a2a2213e4d5ec7d0e736b9
    62369b4de58fb0264aeb710ec6983ceddca5701d
    77418cc6c84ebb0632f8c3448976e82ce612d6b6
    b4eb28dc86ce05eb89b26517167305b994158ef8
    borderline: adapt cppunittest and clang
    
    Change-Id: I4c1b380a76cb37389fab1259a53fb7cc9da982d1

diff --git a/drawinglayer/Library_drawinglayer.mk b/drawinglayer/Library_drawinglayer.mk
index 690c73aaccd9..46012898ddaf 100644
--- a/drawinglayer/Library_drawinglayer.mk
+++ b/drawinglayer/Library_drawinglayer.mk
@@ -68,7 +68,6 @@ $(eval $(call gb_Library_add_exception_objects,drawinglayer,\
     drawinglayer/source/primitive2d/baseprimitive2d \
     drawinglayer/source/primitive2d/bitmapprimitive2d \
     drawinglayer/source/primitive2d/borderlineprimitive2d \
-    drawinglayer/source/primitive2d/clippedborderlineprimitive2d \
     drawinglayer/source/primitive2d/controlprimitive2d \
 	drawinglayer/source/primitive2d/cropprimitive2d \
     drawinglayer/source/primitive2d/discretebitmapprimitive2d \
diff --git a/drawinglayer/qa/unit/border.cxx b/drawinglayer/qa/unit/border.cxx
index 7e8791d19faa..c80d89c6f1b9 100644
--- a/drawinglayer/qa/unit/border.cxx
+++ b/drawinglayer/qa/unit/border.cxx
@@ -16,6 +16,7 @@
 #include <drawinglayer/geometry/viewinformation2d.hxx>
 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
 #include <drawinglayer/primitive2d/polypolygonprimitive2d.hxx>
+#include <drawinglayer/primitive2d/polygonprimitive2d.hxx>
 #include <drawinglayer/processor2d/baseprocessor2d.hxx>
 #include <drawinglayer/processor2d/processorfromoutputdevice.hxx>
 #include <rtl/ref.hxx>
@@ -67,17 +68,15 @@ void DrawinglayerBorderTest::testDoubleDecompositionSolid()
     // Make sure it results in two borders as it's a double one.
     CPPUNIT_ASSERT_EQUAL(static_cast<std::size_t>(2), aContainer.size());
 
-    // Get the inside line.
-    auto pInside = dynamic_cast<const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D*>(aContainer[0].get());
+    // Get the inside line, now a PolygonStrokePrimitive2D
+    auto pInside = dynamic_cast<const drawinglayer::primitive2d::PolygonStrokePrimitive2D*>(aContainer[0].get());
     CPPUNIT_ASSERT(pInside);
 
     // Make sure the inside line's height is fLeftWidth.
-    const basegfx::B2DPolyPolygon& rPolyPolygon = pInside->getB2DPolyPolygon();
-    CPPUNIT_ASSERT_EQUAL(static_cast<sal_uInt32>(1), rPolyPolygon.count());
-    const basegfx::B2DPolygon& rPolygon = rPolyPolygon.getB2DPolygon(0);
-    const basegfx::B2DRange& rRange = rPolygon.getB2DRange();
+    const double fLineWidthFromDecompose = pInside->getLineAttribute().getWidth();
+
     // This was 2.47, i.e. the width of the inner line was 1 unit (in the bugdoc's case: 1 pixel) wider than expected.
-    CPPUNIT_ASSERT_DOUBLES_EQUAL(fLeftWidth, rRange.getHeight(), basegfx::fTools::getSmallValue());
+    CPPUNIT_ASSERT_DOUBLES_EQUAL(fLeftWidth, fLineWidthFromDecompose, basegfx::fTools::getSmallValue());
 }
 
 void DrawinglayerBorderTest::testDoublePixelProcessing()
@@ -95,13 +94,13 @@ void DrawinglayerBorderTest::testDoublePixelProcessing()
     // 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;
@@ -114,31 +113,33 @@ void DrawinglayerBorderTest::testDoublePixelProcessing()
     // Process the primitives.
     pProcessor->process(aPrimitives);
 
-    // Now assert the height of the outer (second) border polygon.
+    // Double line now gets decomposed in Metafile to painting four lines
+    // with width == 0 in a cross pattern due to real line width being between
+    // 1.0 and 2.0. Count created lines
     aMetaFile.Stop();
     aMetaFile.WindStart();
-    bool bFirst = true;
-    sal_Int32 nHeight = 0;
+    sal_uInt32 nPolyLineActionCount = 0;
+
     for (std::size_t nAction = 0; nAction < aMetaFile.GetActionSize(); ++nAction)
     {
         MetaAction* pAction = aMetaFile.GetAction(nAction);
-        if (pAction->GetType() == MetaActionType::POLYPOLYGON)
+
+        if (MetaActionType::POLYLINE == pAction->GetType())
         {
-            if (bFirst)
+            auto pMPLAction = static_cast<MetaPolyLineAction*>(pAction);
+
+            if (0 == pMPLAction->GetLineInfo().GetWidth() && LineStyle::Solid == pMPLAction->GetLineInfo().GetStyle())
             {
-                bFirst = false;
-                continue;
+                nPolyLineActionCount++;
             }
-
-            auto pMPPAction = static_cast<MetaPolyPolygonAction*>(pAction);
-            const tools::PolyPolygon& rPolyPolygon = pMPPAction->GetPolyPolygon();
-            nHeight = rPolyPolygon.GetBoundRect().getHeight();
         }
     }
-    sal_Int32 nExpectedHeight = std::round(fRightWidth);
-    // This was 2, and should be 1: if the logical requested width is 1.47,
-    // then that must be 1 px on the screen, not 2.
-    CPPUNIT_ASSERT_EQUAL(nExpectedHeight, nHeight);
+
+    // Check if all eight (2x four) simple lines with width == 0 and
+    // solid were created
+    const sal_uInt32 nExpectedNumPolyLineActions = 8;
+
+    CPPUNIT_ASSERT_EQUAL(nExpectedNumPolyLineActions, nPolyLineActionCount);
 }
 
 CPPUNIT_TEST_SUITE_REGISTRATION(DrawinglayerBorderTest);
diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 63736d6d2ee1..bd9d5d45b25b 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -41,290 +41,142 @@ T round(T x)
 }
 #endif
 
-namespace drawinglayer {
-
-namespace {
-
-void moveLine(basegfx::B2DPolygon& rPoly, double fGap, const basegfx::B2DVector& rVector)
-{
-    if (basegfx::fTools::equalZero(rVector.getX()))
-    {
-        basegfx::B2DHomMatrix aMat(1, 0, fGap, 0, 1, 0);
-        rPoly.transform(aMat);
-    }
-    else if (basegfx::fTools::equalZero(rVector.getY()))
-    {
-        basegfx::B2DHomMatrix aMat(1, 0, 0, 0, 1, fGap);
-        rPoly.transform(aMat);
-    }
-}
-
-primitive2d::Primitive2DReference makeHairLinePrimitive(
-    const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd, const basegfx::B2DVector& rVector,
-    const basegfx::BColor& rColor, double fGap)
-{
-    basegfx::B2DPolygon aPolygon;
-    aPolygon.append(rStart);
-    aPolygon.append(rEnd);
-    moveLine(aPolygon, fGap, rVector);
-
-    return primitive2d::Primitive2DReference(new primitive2d::PolygonHairlinePrimitive2D(aPolygon, rColor));
-}
-
-primitive2d::Primitive2DReference makeSolidLinePrimitive(
-    const basegfx::B2DPolyPolygon& rClipRegion, const basegfx::B2DPoint& rStart, const basegfx::B2DPoint& rEnd,
-    const basegfx::B2DVector& rVector, const basegfx::BColor& rColor, double fLineWidth, double fGap)
+namespace drawinglayer
 {
-    const basegfx::B2DVector aPerpendicular = basegfx::getPerpendicular(rVector);
-    const basegfx::B2DVector aLineWidthOffset = (fLineWidth * 0.5) * aPerpendicular;
-
-    basegfx::B2DPolygon aPolygon;
-    aPolygon.append(rStart + aLineWidthOffset);
-    aPolygon.append(rEnd + aLineWidthOffset);
-    aPolygon.append(rEnd - aLineWidthOffset);
-    aPolygon.append(rStart - aLineWidthOffset);
-    aPolygon.setClosed(true);
-
-    moveLine(aPolygon, fGap, rVector);
-
-    basegfx::B2DPolyPolygon aClipped =
-        basegfx::tools::clipPolygonOnPolyPolygon(aPolygon, rClipRegion, true, false);
-
-    if (aClipped.count())
-        aPolygon = aClipped.getB2DPolygon(0);
-
-    return primitive2d::Primitive2DReference(
-        new primitive2d::PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aPolygon), rColor));
-}
-
-}
-
-    // fdo#49438: heuristic pseudo hack
-    static bool lcl_UseHairline(double const fW,
-            basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
-            geometry::ViewInformation2D const& rViewInformation)
-    {
-        basegfx::B2DTuple scale;
-        basegfx::B2DTuple translation;
-        double fRotation;
-        double fShear;
-        rViewInformation.getObjectToViewTransformation().decompose(
-                scale, translation, fRotation, fShear);
-        double const fScale(
-            (rEnd.getX() - rStart.getX() > rEnd.getY() - rStart.getY())
-                ? scale.getY() : scale.getX());
-        return (fW * fScale < 0.51);
-    }
-
-    static double lcl_GetCorrectedWidth(double const fW,
-            basegfx::B2DPoint const& rStart, basegfx::B2DPoint const& rEnd,
-            geometry::ViewInformation2D const& rViewInformation)
-    {
-        return (lcl_UseHairline(fW, rStart, rEnd, rViewInformation)) ? 0.0 : fW;
-    }
-
     namespace primitive2d
     {
-        double BorderLinePrimitive2D::getWidth(
-            geometry::ViewInformation2D const& rViewInformation) const
-        {
-            return lcl_GetCorrectedWidth(mfLeftWidth, getStart(), getEnd(),
-                        rViewInformation)
-                 + lcl_GetCorrectedWidth(mfDistance, getStart(), getEnd(),
-                         rViewInformation)
-                 + lcl_GetCorrectedWidth(mfRightWidth, getStart(), getEnd(),
-                         rViewInformation);
-        }
-
-        basegfx::B2DPolyPolygon BorderLinePrimitive2D::getClipPolygon(
-            geometry::ViewInformation2D const& rViewInformation) const
+        // helper to add a centered, maybe stroked line primitive to rContainer
+        void addPolygonStrokePrimitive2D(
+            Primitive2DContainer& rContainer,
+            const basegfx::B2DPoint& rStart,
+            const basegfx::B2DPoint& rEnd,
+            const basegfx::BColor& rColor,
+            double fWidth,
+            editeng::SvxBorderStyle aStyle,
+            double fPatternScale)
         {
-            basegfx::B2DPolygon clipPolygon;
-
-            // Get the vectors
-            basegfx::B2DVector aVector( getEnd() - getStart() );
-            aVector.normalize();
-            const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
+            basegfx::B2DPolygon aPolygon;
 
-            // Get the points
-            const double fWidth(getWidth(rViewInformation));
-            const basegfx::B2DVector aLeftOff(
-                    aPerpendicular * (-0.5 * std::max(fWidth, 1.0)));
-            const basegfx::B2DVector aRightOff(
-                    aPerpendicular * (0.5 * std::max(fWidth, 1.0)));
+            aPolygon.append(rStart);
+            aPolygon.append(rEnd);
 
-            const basegfx::B2DVector aSLVector( aLeftOff - ( getExtendLeftStart() * aVector ) );
-            clipPolygon.append( basegfx::B2DPoint( getStart() + aSLVector * 2.0 ) );
+            const attribute::LineAttribute aLineAttribute(rColor, fWidth);
+            static double fPatScFact(10.0); // 10.0 multiply, see old code
+            const std::vector<double> aDashing(svtools::GetLineDashing(aStyle, fPatternScale * fPatScFact));
 
-            clipPolygon.append( getStart( ) );
-
-            const basegfx::B2DVector aSRVector( aRightOff - ( getExtendRightStart() * aVector ) );
-            clipPolygon.append( basegfx::B2DPoint( getStart() + aSRVector * 2.0 ) );
-
-            const basegfx::B2DVector aERVector( aRightOff + ( getExtendRightEnd() * aVector ) );
-            clipPolygon.append( basegfx::B2DPoint( getEnd() + aERVector * 2.0 ) );
-
-            clipPolygon.append( getEnd( ) );
-
-            const basegfx::B2DVector aELVector( aLeftOff + ( getExtendLeftEnd() * aVector ) );
-            clipPolygon.append( basegfx::B2DPoint( getEnd() + aELVector * 2.0 ) );
-
-            clipPolygon.setClosed( true );
-
-            return basegfx::B2DPolyPolygon( clipPolygon );
-        }
+            if (aDashing.empty())
+            {
+                rContainer.push_back(
+                    new PolygonStrokePrimitive2D(
+                        aPolygon,
+                        aLineAttribute));
+            }
+            else
+            {
+                const attribute::StrokeAttribute aStrokeAttribute(aDashing);
 
-        Primitive2DContainer BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
-        {
-            return createDecomposition(rViewInformation, false);
+                rContainer.push_back(
+                    new PolygonStrokePrimitive2D(
+                        aPolygon,
+                        aLineAttribute,
+                        aStrokeAttribute));
+            }
         }
 
-        Primitive2DContainer BorderLinePrimitive2D::createDecomposition(const geometry::ViewInformation2D& rViewInformation, bool bPixelCorrection) const
+        Primitive2DContainer BorderLinePrimitive2D::create2DDecomposition(const geometry::ViewInformation2D& /*rViewInformation*/) const
         {
-            Primitive2DContainer xRetval;
+            Primitive2DContainer aContainer;
 
-            if(!getStart().equal(getEnd()) && ( isInsideUsed() || isOutsideUsed() ) )
+            if (!getStart().equal(getEnd()) && (isInsideUsed() || isOutsideUsed()))
             {
                 // get data and vectors
                 basegfx::B2DVector aVector(getEnd() - getStart());
                 aVector.normalize();
                 const basegfx::B2DVector aPerpendicular(basegfx::getPerpendicular(aVector));
 
-                const basegfx::B2DPolyPolygon& aClipRegion =
-                    getClipPolygon(rViewInformation);
-
-                if(isOutsideUsed() && isInsideUsed())
+                if (isOutsideUsed() && isInsideUsed())
                 {
-                    const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped later.
-                    const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector));
-                    const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector));
-
-                    xRetval.resize(2);
-
-                    double fLeftWidth = getLeftWidth();
-                    bool bLeftHairline = lcl_UseHairline(fLeftWidth, getStart(), getEnd(), rViewInformation);
-                    if (bLeftHairline)
-                        fLeftWidth = 0.0;
-
-                    double fRightWidth = getRightWidth();
-                    bool bRightHairline = lcl_UseHairline(fRightWidth, getStart(), getEnd(), rViewInformation);
-                    if (bRightHairline)
-                        fRightWidth = 0.0;
-
-                    // "inside" line
-
-                    if (bLeftHairline)
-                        xRetval[0] = makeHairLinePrimitive(
-                            getStart(), getEnd(), aVector, getRGBColorLeft(), 0.0);
-                    else
+                    // double line with gap. Use mfDiscreteDistance (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
+                    if (isInsideUsed())
                     {
-                        double fWidth = bPixelCorrection ? std::round(fLeftWidth) : fLeftWidth;
-                        xRetval[0] = makeSolidLinePrimitive(
-                            aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorLeft(), fWidth, -fLeftWidth/2.0);
+                        // inside line (left). Create stroke primitive centered on line width
+                        const double fDeltaY((mfDiscreteDistance + getLeftWidth()) * 0.5);
+                        const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
+                        const basegfx::B2DPoint aStart(getStart() - (aVector * getExtendLeftStart()) - aDeltaY);
+                        const basegfx::B2DPoint aEnd(getEnd() + (aVector * getExtendLeftEnd()) - aDeltaY);
+
+                        addPolygonStrokePrimitive2D(
+                            aContainer,
+                            aStart,
+                            aEnd,
+                            getRGBColorLeft(),
+                            getLeftWidth(),
+                            getStyle(),
+                            getPatternScale());
                     }
 
-                    // "outside" line
-
-                    if (bRightHairline)
-                        xRetval[1] = makeHairLinePrimitive(
-                            getStart(), getEnd(), aVector, getRGBColorRight(), fLeftWidth+mfDistance);
-                    else
+                    if (hasGapColor() && isDistanceUsed())
                     {
-                        double fWidth = bPixelCorrection ? std::round(fRightWidth) : fRightWidth;
-                        xRetval[1] = makeSolidLinePrimitive(
-                            aClipRegion, aTmpStart, aTmpEnd, aVector, getRGBColorRight(), fWidth, mfDistance+fRightWidth/2.0);
+                        // gap (if visible, found no practicval usage).
+                        // Create stroke primitive on vector with given color
+                        addPolygonStrokePrimitive2D(
+                            aContainer,
+                            getStart(),
+                            getEnd(),
+                            getRGBColorGap(),
+                            mfDiscreteDistance,
+                            getStyle(),
+                            getPatternScale());
                     }
-                }
-                else
-                {
-                    // single line, create geometry
-                    basegfx::B2DPolygon aPolygon;
-                    const double fExt = getWidth(rViewInformation);  // Extend a lot: it'll be clipped after
-                    const basegfx::B2DPoint aTmpStart(getStart() - (fExt * aVector));
-                    const basegfx::B2DPoint aTmpEnd(getEnd() + (fExt * aVector));
-
-                    // Get which is the line to show
-                    bool bIsSolidline = isSolidLine();
-                    double nWidth = getLeftWidth();
-                    basegfx::BColor aColor = getRGBColorLeft();
-                    if ( basegfx::fTools::equal( 0.0, mfLeftWidth ) )
-                    {
-                        nWidth = getRightWidth();
-                        aColor = getRGBColorRight();
-                    }
-                    bool const bIsHairline = lcl_UseHairline(
-                            nWidth, getStart(), getEnd(), rViewInformation);
-                    nWidth = lcl_GetCorrectedWidth(nWidth,
-                                getStart(), getEnd(), rViewInformation);
 
-                    if(bIsHairline && bIsSolidline)
+                    if (isOutsideUsed())
                     {
-                        // create hairline primitive
-                        aPolygon.append( getStart() );
-                        aPolygon.append( getEnd() );
-
-                        xRetval.resize(1);
-                        xRetval[0] = Primitive2DReference(new PolygonHairlinePrimitive2D(
-                            aPolygon,
-                            aColor));
-                    }
-                    else
-                    {
-                        // create filled polygon primitive
-                        const basegfx::B2DVector aLineWidthOffset(((nWidth + 1) * 0.5) * aPerpendicular);
-
-                        aPolygon.append( aTmpStart );
-                        aPolygon.append( aTmpEnd );
-
-                        basegfx::B2DPolyPolygon aDashed =
-                            svtools::ApplyLineDashing(aPolygon, getStyle(), mfPatternScale*10.0);
-
-                        for (sal_uInt32 i = 0; i < aDashed.count(); i++ )
-                        {
-                            basegfx::B2DPolygon aDash = aDashed.getB2DPolygon( i );
-                            basegfx::B2DPoint aDashStart = aDash.getB2DPoint( 0 );
-                            basegfx::B2DPoint aDashEnd = aDash.getB2DPoint( aDash.count() - 1 );
-
-                            basegfx::B2DPolygon aDashPolygon;
-                            aDashPolygon.append( aDashStart + aLineWidthOffset );
-                            aDashPolygon.append( aDashEnd + aLineWidthOffset );
-                            aDashPolygon.append( aDashEnd - aLineWidthOffset );
-                            aDashPolygon.append( aDashStart - aLineWidthOffset );
-                            aDashPolygon.setClosed( true );
-
-                            basegfx::B2DPolyPolygon aClipped = basegfx::tools::clipPolygonOnPolyPolygon(
-                                aDashPolygon, aClipRegion, true, false );
-
-                            if ( aClipped.count() )
-                                aDashed.setB2DPolygon( i, aClipped.getB2DPolygon( 0 ) );
-                        }
-
-                        sal_uInt32 n = aDashed.count();
-                        xRetval.resize(n);
-                        for (sal_uInt32 i = 0; i < n; ++i)
-                        {
-                            basegfx::B2DPolygon aDash = aDashed.getB2DPolygon(i);
-                            if (bIsHairline)
-                            {
-                                // Convert a rectangular polygon into a line.
-                                basegfx::B2DPolygon aDash2;
-                                basegfx::B2DRange aRange = aDash.getB2DRange();
-                                aDash2.append(basegfx::B2DPoint(aRange.getMinX(), aRange.getMinY()));
-                                aDash2.append(basegfx::B2DPoint(aRange.getMaxX(), aRange.getMinY()));
-                                xRetval[i] = Primitive2DReference(
-                                    new PolygonHairlinePrimitive2D(aDash2, aColor));
-                            }
-                            else
-                            {
-                                xRetval[i] = Primitive2DReference(
-                                    new PolyPolygonColorPrimitive2D(basegfx::B2DPolyPolygon(aDash), aColor));
-                            }
-                        }
+                        // outside line (right). Create stroke primitive centered on line width
+                        const double fDeltaY((mfDiscreteDistance + getRightWidth()) * 0.5);
+                        const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
+                        const basegfx::B2DPoint aStart(getStart() - (aVector * getExtendRightStart()) + aDeltaY);
+                        const basegfx::B2DPoint aEnd(getEnd() + (aVector * getExtendRightEnd()) + aDeltaY);
+
+                        addPolygonStrokePrimitive2D(
+                            aContainer,
+                            aStart,
+                            aEnd,
+                            getRGBColorRight(),
+                            getRightWidth(),
+                            getStyle(),
+                            getPatternScale());
                     }
                 }
+                else if(isInsideUsed())
+                {
+                    // single line, only inside values used, no vertical offsets
+                    addPolygonStrokePrimitive2D(
+                        aContainer,
+                        getStart(),
+                        getEnd(),
+                        getRGBColorLeft(),
+                        getLeftWidth(),
+                        getStyle(),
+                        getPatternScale());
+                }
+            }
+
+            return aContainer;
+        }
+
+        bool BorderLinePrimitive2D::isHorizontalOrVertical(const geometry::ViewInformation2D& rViewInformation) const
+        {
+            if (!getStart().equal(getEnd()))
+            {
+                const basegfx::B2DHomMatrix& rOTVT = rViewInformation.getObjectToViewTransformation();
+                const basegfx::B2DVector aVector(rOTVT * getEnd() - rOTVT * getStart());
+
+                return basegfx::fTools::equalZero(aVector.getX()) || basegfx::fTools::equalZero(aVector.getY());
             }
 
-            return xRetval;
+            return false;
         }
 
         BorderLinePrimitive2D::BorderLinePrimitive2D(
@@ -358,7 +210,8 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive(
             maRGBColorGap(rRGBColorGap),
             mbHasGapColor(bHasGapColor),
             mnStyle(nStyle),
-            mfPatternScale(fPatternScale)
+            mfPatternScale(fPatternScale),
+            mfDiscreteDistance(0.0)
         {
         }
 
@@ -388,6 +241,42 @@ primitive2d::Primitive2DReference makeSolidLinePrimitive(
             return false;
         }
 
+        Primitive2DContainer BorderLinePrimitive2D::get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const
+        {
+            ::osl::MutexGuard aGuard(m_aMutex);
+
+            if (!getStart().equal(getEnd()) && isOutsideUsed() && isInsideUsed())
+            {
+                // Double line with gap. In this case, we want to be view-dependent.
+                // Get the current DiscreteUnit, look at X and Y and use the maximum
+                const basegfx::B2DVector aDiscreteVector(rViewInformation.getInverseObjectToViewTransformation() * basegfx::B2DVector(1.0, 1.0));
+                const double fDiscreteUnit(std::min(fabs(aDiscreteVector.getX()), fabs(aDiscreteVector.getY())));
+
+                // When discrete unit is bigger than distance (distance is less than one pixel),
+                // force distance to one pixel. Or expressed different, do not let the distance
+                // get smaller than one pixel. This is done for screen rendering and compatibility.
+                // This can also be done using DiscreteMetricDependentPrimitive2D as base class
+                // for this class, but specialization is better here for later buffering (only
+                // do this when 'double line with gap')
+                const double fNewDiscreteDistance(std::max(fDiscreteUnit, getDistance()));
+
+                if (!rtl::math::approxEqual(fNewDiscreteDistance, mfDiscreteDistance))
+                {
+                    if (!getBuffered2DDecomposition().empty())
+                    {
+                        // conditions of last local decomposition have changed, delete
+                        const_cast< BorderLinePrimitive2D* >(this)->setBuffered2DDecomposition(Primitive2DContainer());
+                    }
+
+                    // remember value for usage in create2DDecomposition
+                    const_cast< BorderLinePrimitive2D* >(this)->mfDiscreteDistance = fNewDiscreteDistance;
+                }
+            }
+
+            // call base implementation
+            return BufferedDecompositionPrimitive2D::get2DDecomposition(rViewInformation);
+        }
+
         // provide unique ID
         ImplPrimitive2DIDBlock(BorderLinePrimitive2D, PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D)
 
diff --git a/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx
deleted file mode 100644
index 5a19ee88fc5a..000000000000
--- a/drawinglayer/source/primitive2d/clippedborderlineprimitive2d.cxx
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-#include <drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx>
-#include <drawinglayer/primitive2d/drawinglayer_primitivetypes2d.hxx>
-
-namespace drawinglayer
-{
-    namespace primitive2d
-    {
-        basegfx::B2DPolyPolygon ClippedBorderLinePrimitive2D::getClipPolygon(
-            SAL_UNUSED_PARAMETER geometry::ViewInformation2D const&) const
-        {
-            basegfx::B2DPolyPolygon aPolyPolygon;
-            aPolyPolygon.append( maIntersection );
-            return aPolyPolygon;
-        }
-
-        ClippedBorderLinePrimitive2D::ClippedBorderLinePrimitive2D(
-            const basegfx::B2DPoint& rStart,
-            const basegfx::B2DPoint& rEnd,
-            double fLeftWidth,
-            double fDistance,
-            double fRightWidth,
-            const basegfx::B2DPolygon& rIntersection,
-            const basegfx::BColor& rRGBColorRight,
-            const basegfx::BColor& rRGBColorLeft,
-            const basegfx::BColor& rRGBColorGap,
-            bool bHasGapColor,
-            const short nStyle,
-            double fPatternScale)
-        :   BorderLinePrimitive2D( rStart, rEnd, fLeftWidth,fDistance, fRightWidth,
-                        0.0, 0.0, 0.0, 0.0, rRGBColorRight, rRGBColorLeft,
-                        rRGBColorGap, bHasGapColor, nStyle, fPatternScale),
-            maIntersection( rIntersection )
-        {
-        }
-
-        bool ClippedBorderLinePrimitive2D::operator==(const BasePrimitive2D& rPrimitive) const
-        {
-            if(BorderLinePrimitive2D::operator==(rPrimitive))
-            {
-                const ClippedBorderLinePrimitive2D& rCompare = static_cast<const ClippedBorderLinePrimitive2D&>(rPrimitive);
-
-                return maIntersection == rCompare.maIntersection;
-            }
-
-            return false;
-        }
-
-        // provide unique ID
-        ImplPrimitive2DIDBlock(ClippedBorderLinePrimitive2D, PRIMITIVE2D_ID_CLIPPEDBORDERLINEPRIMITIVE2D)
-
-
-    } // namespace primitive2d
-} // namespace drawinglayer
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
index 2e6bc257b337..80f4ab6e0618 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.cxx
@@ -59,34 +59,6 @@
 
 using namespace com::sun::star;
 
-namespace {
-
-basegfx::B2DPolygon makeRectPolygon( double fX, double fY, double fW, double fH )
-{
-    basegfx::B2DPolygon aPoly;
-    aPoly.append(basegfx::B2DPoint(fX, fY));
-    aPoly.append(basegfx::B2DPoint(fX+fW, fY));
-    aPoly.append(basegfx::B2DPoint(fX+fW, fY+fH));
-    aPoly.append(basegfx::B2DPoint(fX, fY+fH));
-    aPoly.setClosed(true);
-    return aPoly;
-}
-
-void drawHairLine(
-    OutputDevice* pOutDev, double fX1, double fY1, double fX2, double fY2,
-    const basegfx::BColor& rColor )
-{
-    basegfx::B2DPolygon aTarget;
-    aTarget.append(basegfx::B2DPoint(fX1, fY1));
-    aTarget.append(basegfx::B2DPoint(fX2, fY2));
-
-    pOutDev->SetFillColor();
-    pOutDev->SetLineColor(Color(rColor));
-    pOutDev->DrawPolyLine(aTarget);
-}
-
-}
-
 namespace drawinglayer
 {
     namespace processor2d
@@ -277,341 +249,6 @@ namespace drawinglayer
             return bTryWorked;
         }
 
-        bool VclPixelProcessor2D::tryDrawBorderLinePrimitive2DDirect(
-            const drawinglayer::primitive2d::BorderLinePrimitive2D& rSource)
-        {
-            const basegfx::B2DPoint& rS = rSource.getStart();
-            const basegfx::B2DPoint& rE = rSource.getEnd();
-
-            double fX1 = rS.getX();
-            double fY1 = rS.getY();
-            double fX2 = rE.getX();
-            double fY2 = rE.getY();
-
-            bool bHorizontal = false;
-            if (fX1 == fX2)
-            {
-                // Vertical line.
-            }
-            else if (fY1 == fY2)
-            {
-                // Horizontal line.
-                bHorizontal = true;
-            }
-            else
-                // Neither.  Bail out.
-                return false;
-
-            switch (rSource.getStyle())
-            {
-                case table::BorderLineStyle::SOLID:
-                case table::BorderLineStyle::DOUBLE_THIN:
-                {
-                    const basegfx::BColor aLineColor =
-                        maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft());
-                    double nThick = rtl::math::round(rSource.getLeftWidth());
-
-                    bool bDouble = rSource.getStyle() == table::BorderLineStyle::DOUBLE_THIN;
-
-                    basegfx::B2DPolygon aTarget;
-
-                    if (bHorizontal)
-                    {
-                        // Horizontal line.  Draw it as a rectangle.
-
-                        aTarget = makeRectPolygon(fX1, fY1, fX2-fX1, nThick);
-                        aTarget.transform(maCurrentTransformation);
-
-                        basegfx::B2DRange aRange = aTarget.getB2DRange();
-                        double fH = aRange.getHeight();
-
-                        if (bDouble)
-                        {
-                            // Double line
-                            drawHairLine(
-                                mpOutputDevice, aRange.getMinX(), aRange.getMinY()-1.0, aRange.getMaxX(), aRange.getMinY()-1.0,
-                                aLineColor);
-
-                            drawHairLine(
-                                mpOutputDevice, aRange.getMinX(), aRange.getMinY()+1.0, aRange.getMaxX(), aRange.getMinY()+1.0,
-                                aLineColor);
-
-                            return true;
-                        }
-
-                        if (fH <= 1.0)
-                        {
-                            // Draw it as a line.
-                            drawHairLine(
-                                mpOutputDevice, aRange.getMinX(), aRange.getMinY(), aRange.getMaxX(), aRange.getMinY(),
-                                aLineColor);
-
-                            return true;
-                        }
-
-                        double fOffset = rtl::math::round(fH/2.0, 0, rtl_math_RoundingMode_Down);
-                        if (fOffset != 0.0)
-                        {
-                            // Move it up a bit to align it vertically centered.
-                            basegfx::B2DHomMatrix aMat;
-                            aMat.set(1, 2, -fOffset);
-                            aTarget.transform(aMat);
-                        }
-                    }
-                    else
-                    {
-                        // Vertical line.  Draw it as a rectangle.
-
-                        aTarget = makeRectPolygon(fX1, fY1, nThick, fY2-fY1);
-                        aTarget.transform(maCurrentTransformation);
-
-                        basegfx::B2DRange aRange = aTarget.getB2DRange();
-                        double fW = aRange.getWidth();
-
-                        if (bDouble)
-                        {
-                            // Draw it as a line.
-                            drawHairLine(
-                                mpOutputDevice, aRange.getMinX()-1.0, aRange.getMinY(), aRange.getMinX()-1.0, aRange.getMaxY(),
-                                aLineColor);
-
-                            drawHairLine(
-                                mpOutputDevice, aRange.getMinX()+1.0, aRange.getMinY(), aRange.getMinX()+1.0, aRange.getMaxY(),
-                                aLineColor);
-
-                            return true;
-                        }
-
-                        if (fW <= 1.0)
-                        {
-                            // Draw it as a line.
-                            drawHairLine(
-                                mpOutputDevice, aRange.getMinX(), aRange.getMinY(), aRange.getMinX(), aRange.getMaxY(),
-                                aLineColor);
-
-                            return true;
-                        }
-
-                        double fOffset = rtl::math::round(fW/2.0, 0, rtl_math_RoundingMode_Down);
-                        if (fOffset != 0.0)
-                        {
-                            // Move it to the left a bit to center it horizontally.
-                            basegfx::B2DHomMatrix aMat;
-                            aMat.set(0, 2, -fOffset);
-                            aTarget.transform(aMat);
-                        }
-                    }
-
-                    mpOutputDevice->SetFillColor(Color(aLineColor));
-                    mpOutputDevice->SetLineColor();
-                    mpOutputDevice->DrawPolygon(aTarget);
-                    return true;
-                }
-                break;
-                case table::BorderLineStyle::DOTTED:
-                case table::BorderLineStyle::DASHED:
-                case table::BorderLineStyle::DASH_DOT:
-                case table::BorderLineStyle::DASH_DOT_DOT:
-                case table::BorderLineStyle::FINE_DASHED:
-                {
-                    std::vector<double> aPattern =
-                        svtools::GetLineDashing(rSource.getStyle(), rSource.getPatternScale()*10.0);
-
-                    if (aPattern.empty())
-                        // Failed to get pattern values.
-                        return false;
-
-                    double nThick = rtl::math::round(rSource.getLeftWidth());
-
-                    const basegfx::BColor aLineColor =
-                        maBColorModifierStack.getModifiedColor(rSource.getRGBColorLeft());
-
-                    // Transform the current line range before using it for rendering.
-                    basegfx::B2DRange aRange(fX1, fY1, fX2, fY2);
-                    aRange.transform(maCurrentTransformation);
-                    fX1 = aRange.getMinX();
-                    fX2 = aRange.getMaxX();
-                    fY1 = aRange.getMinY();
-                    fY2 = aRange.getMaxY();
-
-                    basegfx::B2DPolyPolygon aTarget;
-
-                    if (bHorizontal)
-                    {
-                        // Horizontal line.
-
-                        if (basegfx::fTools::equalZero(nThick))
-                        {
-                            // Dash line segment too small to draw.  Substitute it with a solid line.
-                            drawHairLine(mpOutputDevice, fX1, fY1, fX2, fY1, aLineColor);
-                            return true;
-                        }
-
-                        // Create a dash unit polygon set.
-                        basegfx::B2DPolyPolygon aDashes;
-                        std::vector<double>::const_iterator it = aPattern.begin(), itEnd = aPattern.end();
-                        for (; it != itEnd; ++it)
-                            aDashes.append(makeRectPolygon(0, 0, *it, nThick));
-
-                        aDashes.transform(maCurrentTransformation);
-                        rtl::math::setNan(&nThick);
-
-                        // Pixelize the dash unit.  We use the same height for
-                        // all dash polygons.
-                        basegfx::B2DPolyPolygon aDashesPix;
-
-                        for (sal_uInt32 i = 0, n = aDashes.count(); i < n; ++i)
-                        {
-                            basegfx::B2DPolygon aPoly = aDashes.getB2DPolygon(i);
-                            aRange = aPoly.getB2DRange();
-                            double fW = rtl::math::round(aRange.getWidth());
-                            if (basegfx::fTools::equalZero(fW))
-                            {
-                                // Dash line segment too small to draw.  Substitute it with a solid line.
-                                drawHairLine(mpOutputDevice, fX1, fY1, fX2, fY1, aLineColor);
-                                return true;
-                            }
-
-                            if (rtl::math::isNan(nThick))
-                                nThick = rtl::math::round(aRange.getHeight());
-
-                            aDashesPix.append(makeRectPolygon(0, 0, fW, nThick));
-                        }
-
-                        // Make all dash polygons and render them.
-                        double fX = fX1;
-                        bool bLine = true;
-                        sal_uInt32 i = 0, n = aDashesPix.count();
-                        while (fX <= fX2)
-                        {
-                            basegfx::B2DPolygon aPoly = aDashesPix.getB2DPolygon(i);
-                            aRange = aPoly.getB2DRange();
-                            if (bLine)
-                            {
-                                double fBlockW = aRange.getWidth();
-                                if (fX + fBlockW > fX2)
-                                    // Clip the right end in case it spills over the range.
-                                    fBlockW = fX2 - fX + 1;
-
-                                double fH = aRange.getHeight();
-                                if (basegfx::fTools::equalZero(fH))
-                                    fH = 1.0;
-
-                                aTarget.append(makeRectPolygon(fX, fY1, fBlockW, fH));
-                            }
-
-                            bLine = !bLine; // line and blank alternate.
-                            fX += aRange.getWidth();
-
-                            ++i;
-                            if (i >= n)
-                                i = 0;
-                        }
-
-                        double fOffset = rtl::math::round(nThick/2.0, 0, rtl_math_RoundingMode_Down);
-                        if (fOffset != 0.0)
-                        {
-                            // Move it up a bit to align it vertically centered.
-                            basegfx::B2DHomMatrix aMat;
-                            aMat.set(1, 2, -fOffset);
-                            aTarget.transform(aMat);
-                        }
-                    }
-                    else
-                    {
-                        // Vertical line.
-
-                        if (basegfx::fTools::equalZero(nThick))
-                        {
-                            // Dash line segment too small to draw.  Substitute it with a solid line.
-                            drawHairLine(mpOutputDevice, fX1, fY1, fX1, fY2, aLineColor);
-                            return true;
-                        }
-
-                        // Create a dash unit polygon set.
-                        basegfx::B2DPolyPolygon aDashes;
-                        std::vector<double>::const_iterator it = aPattern.begin(), itEnd = aPattern.end();
-                        for (; it != itEnd; ++it)
-                            aDashes.append(makeRectPolygon(0, 0, nThick, *it));
-
-                        aDashes.transform(maCurrentTransformation);
-                        rtl::math::setNan(&nThick);
-
-                        // Pixelize the dash unit.  We use the same width for
-                        // all dash polygons.
-                        basegfx::B2DPolyPolygon aDashesPix;
-
-                        for (sal_uInt32 i = 0, n = aDashes.count(); i < n; ++i)
-                        {
-                            basegfx::B2DPolygon aPoly = aDashes.getB2DPolygon(i);
-                            aRange = aPoly.getB2DRange();
-                            double fH = rtl::math::round(aRange.getHeight());
-                            if (basegfx::fTools::equalZero(fH))
-                            {
-                                // Dash line segment too small to draw.  Substitute it with a solid line.
-                                drawHairLine(mpOutputDevice, fX1, fY1, fX1, fY2, aLineColor);
-                                return true;
-                            }
-
-                            if (rtl::math::isNan(nThick))
-                                nThick = rtl::math::round(aRange.getWidth());
-
-                            aDashesPix.append(makeRectPolygon(0, 0, nThick, fH));
-                        }
-
-                        // Make all dash polygons and render them.
-                        double fY = fY1;
-                        bool bLine = true;
-                        sal_uInt32 i = 0, n = aDashesPix.count();
-                        while (fY <= fY2)
-                        {
-                            basegfx::B2DPolygon aPoly = aDashesPix.getB2DPolygon(i);
-                            aRange = aPoly.getB2DRange();
-                            if (bLine)
-                            {
-                                double fBlockH = aRange.getHeight();
-                                if (fY + fBlockH > fY2)
-                                    // Clip the bottom end in case it spills over the range.
-                                    fBlockH = fY2 - fY + 1;
-
-                                double fW = aRange.getWidth();
-                                if (basegfx::fTools::equalZero(fW))
-                                    fW = 1.0;
-
-                                aTarget.append(makeRectPolygon(fX1, fY, fW, fBlockH));
-                            }
-
-                            bLine = !bLine; // line and blank alternate.
-                            fY += aRange.getHeight();
-
-                            ++i;
-                            if (i >= n)
-                                i = 0;
-                        }
-
-                        double fOffset = rtl::math::round(nThick/2.0, 0, rtl_math_RoundingMode_Down);
-                        if (fOffset != 0.0)
-                        {
-                            // Move it to the left a bit to center it horizontally.
-                            basegfx::B2DHomMatrix aMat;
-                            aMat.set(0, 2, -fOffset);
-                            aTarget.transform(aMat);
-                        }
-                    }
-
-                    mpOutputDevice->SetFillColor(Color(aLineColor));
-                    mpOutputDevice->SetLineColor();
-                    mpOutputDevice->DrawPolyPolygon(aTarget);
-
-                    return true;
-                }
-                break;
-                default:
-                    ;
-            }
-            return false;
-        }
-
         void VclPixelProcessor2D::processBasePrimitive2D(const primitive2d::BasePrimitive2D& rCandidate)
         {
             switch(rCandidate.getPrimitive2DID())
@@ -1224,24 +861,25 @@ namespace drawinglayer
                 }
                 case PRIMITIVE2D_ID_BORDERLINEPRIMITIVE2D:
                 {
-                    // process recursively, but turn off anti-aliasing. Border
-                    // lines are always rectangular, and look horrible when
-                    // the anti-aliasing is enabled.
-                    AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing();
-                    mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
-
+                    // process recursively, but switch off AntiAliasing for
+                    // horizontal/vertical lines (*not* diagonal lines).
+                    // Checked using AntialiasingFlags::PixelSnapHairline instead,
+                    // but with AntiAliasing on the display really is too 'ghosty' when
+                    // using fine stroking. Correct, but 'ghosty'.
                     const drawinglayer::primitive2d::BorderLinePrimitive2D& rBorder =
                         static_cast<const drawinglayer::primitive2d::BorderLinePrimitive2D&>(rCandidate);
 
-                    if (!tryDrawBorderLinePrimitive2DDirect(rBorder))
+                    if (rBorder.isHorizontalOrVertical(getViewInformation2D()))
                     {
-                        if (rBorder.getStyle() == table::BorderLineStyle::DOUBLE)
-                            process(rBorder.createDecomposition(getViewInformation2D(), true));
-                        else
-                            process(rCandidate.get2DDecomposition(getViewInformation2D()));
+                        AntialiasingFlags nAntiAliasing = mpOutputDevice->GetAntialiasing();
+                        mpOutputDevice->SetAntialiasing(nAntiAliasing & ~AntialiasingFlags::EnableB2dDraw);
+                        process(rCandidate.get2DDecomposition(getViewInformation2D()));
+                        mpOutputDevice->SetAntialiasing(nAntiAliasing);
+                    }
+                    else
+                    {
+                        process(rCandidate.get2DDecomposition(getViewInformation2D()));
                     }
-
-                    mpOutputDevice->SetAntialiasing(nAntiAliasing);
                     break;
                 }
                 default :
diff --git a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
index f7b6748bb3e2..be64d033d18b 100644
--- a/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
+++ b/drawinglayer/source/processor2d/vclpixelprocessor2d.hxx
@@ -64,7 +64,6 @@ namespace drawinglayer
             bool tryDrawPolyPolygonColorPrimitive2DDirect(const drawinglayer::primitive2d::PolyPolygonColorPrimitive2D& rSource, double fTransparency);
             bool tryDrawPolygonHairlinePrimitive2DDirect(const drawinglayer::primitive2d::PolygonHairlinePrimitive2D& rSource, double fTransparency);
             bool tryDrawPolygonStrokePrimitive2DDirect(const drawinglayer::primitive2d::PolygonStrokePrimitive2D& rSource, double fTransparency);
-            bool tryDrawBorderLinePrimitive2DDirect(const drawinglayer::primitive2d::BorderLinePrimitive2D& rSource);
 
         public:
             /// constructor/destructor
diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
index 5c73edc6e430..8c7fb25cf87d 100644
--- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
@@ -28,7 +28,7 @@
 #include <basegfx/polygon/b2dpolypolygon.hxx>
 
 #include <com/sun/star/table/BorderLineStyle.hpp>
-
+namespace editeng { typedef sal_Int16 SvxBorderStyle; }
 
 namespace drawinglayer
 {
@@ -66,22 +66,23 @@ namespace drawinglayer
             basegfx::BColor                                 maRGBColorGap;
             bool                                            mbHasGapColor;
 
-            short                                           mnStyle;
-
+            editeng::SvxBorderStyle                         mnStyle;
             double                                          mfPatternScale;
 
-            /// local helpers
-            double getWidth(
-                    const geometry::ViewInformation2D& rViewInformation) const;
+            // for view dependent decomposition in the case with distance (gap),
+            // remember the last used concrete mfDistance, see get2DDecomposition
+            // implementation
+            double                                          mfDiscreteDistance;
 
-            bool isSolidLine() const
+            /// local helpers
+            bool isInsideUsed() const
             {
-                return mnStyle == css::table::BorderLineStyle::SOLID;
+                return !basegfx::fTools::equalZero(mfLeftWidth);
             }
 
-            bool isInsideUsed() const
+            bool isDistanceUsed() const
             {
-                return !basegfx::fTools::equalZero(mfLeftWidth);
+                return !basegfx::fTools::equalZero(mfDistance);
             }
 
             bool isOutsideUsed() const
@@ -89,10 +90,6 @@ namespace drawinglayer
                 return !basegfx::fTools::equalZero(mfRightWidth);
             }
 
-        protected:
-            virtual basegfx::B2DPolyPolygon getClipPolygon(
-                    const geometry::ViewInformation2D& rViewInformation) const;
-
             /// create local decomposition
             virtual Primitive2DContainer create2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
 
@@ -131,12 +128,16 @@ namespace drawinglayer
             bool hasGapColor( ) const { return mbHasGapColor; }
             short getStyle () const { return mnStyle; }
             double getPatternScale() const { return mfPatternScale; }
-            /// Same as create2DDecomposition(), but can do pixel correction if requested.
-            Primitive2DContainer createDecomposition(const geometry::ViewInformation2D& rViewInformation, bool bPixelCorrection) const;
+
+            /// helper to decide if AntiAliasing should be used
+            bool isHorizontalOrVertical(const geometry::ViewInformation2D& rViewInformation) const;
 
             /// compare operator
             virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
 
+            /// Override standard getDecomposition to be view-dependent here
+            virtual Primitive2DContainer get2DDecomposition(const geometry::ViewInformation2D& rViewInformation) const override;
+
             /// provide unique ID
             DeclPrimitive2DIDBlock()
         };
diff --git a/include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx
deleted file mode 100644
index 62bd9813698a..000000000000
--- a/include/drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx
+++ /dev/null
@@ -1,65 +0,0 @@
-/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
-/*
- * This file is part of the LibreOffice project.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-
-#ifndef INCLUDED_DRAWINGLAYER_PRIMITIVE2D_CLIPPEDBORDERLINEPRIMITIVE2D_HXX
-#define INCLUDED_DRAWINGLAYER_PRIMITIVE2D_CLIPPEDBORDERLINEPRIMITIVE2D_HXX
-
-#include <drawinglayer/drawinglayerdllapi.h>
-
-#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
-#include <basegfx/polygon/b2dpolypolygon.hxx>
-#include <basegfx/polygon/b2dpolygon.hxx>
-
-
-namespace drawinglayer
-{
-    namespace primitive2d
-    {
-        /** BorderLinePrimitive2D clipped by the intersection with a provided
-            polygon.
-         */
-        class DRAWINGLAYER_DLLPUBLIC ClippedBorderLinePrimitive2D : public BorderLinePrimitive2D
-        {
-        private:
-            const basegfx::B2DPolygon maIntersection;
-
-        protected:
-            virtual basegfx::B2DPolyPolygon getClipPolygon(
-                    const geometry::ViewInformation2D& rViewInformation) const override;
-
-        public:
-            /// constructor
-            ClippedBorderLinePrimitive2D(
-                const basegfx::B2DPoint& rStart,
-                const basegfx::B2DPoint& rEnd,
-                double fLeftWidth,
-                double fDistance,
-                double fRightWidth,
-                const basegfx::B2DPolygon& rIntersection,
-                const basegfx::BColor& rRGBColorRight,
-                const basegfx::BColor& rRGBColorLeft,
-                const basegfx::BColor& rRGBColorGap,
-                bool bHasGapColor,
-                const short nStyle,
-                double fPatternScale = 1.0 );
-
-            /// compare operator
-            virtual bool operator==(const BasePrimitive2D& rPrimitive) const override;
-
-            /// provide unique ID
-            DeclPrimitive2DIDBlock()
-        };
-    } // end of namespace primitive2d
-} // end of namespace drawinglayer
-
-
-#endif //INCLUDED_DRAWINGLAYER_PRIMITIVE2D_CLIPPEDBORDERLINEPRIMITIVE2D_HXX
-
-
-/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx
index e7ac85c3b7d4..9f6d25f786b0 100644
--- a/include/svx/framelink.hxx
+++ b/include/svx/framelink.hxx
@@ -429,7 +429,7 @@ SVX_DLLPUBLIC bool CheckFrameBorderConnectable(
                     |       \                       /       |
                  rLFromB      \                   /      rRFromB
  */
-SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimitives(
+SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DReference CreateBorderPrimitives(
     const Point&        rLPos,          /// Reference point for left end of the processed frame border.
     const Point&        rRPos,          /// Reference point for right end of the processed frame border.
     const Style&        rBorder,        /// Style of the processed frame border.
@@ -451,7 +451,7 @@ SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimit
     const long          rRotationB = 9000  /// Angle of the bottom slanted frames in 100th of degree
 );
 
-SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimitives(
+SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DReference CreateBorderPrimitives(
     const Point&        rLPos,          /// Reference point for left end of the processed frame border.
     const Point&        rRPos,          /// Reference point for right end of the processed frame border.
     const Style&        rBorder,        /// Style of the processed frame border.
@@ -469,10 +469,6 @@ SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimit
     const long          rRotationB = 9000  /// Angle of the bottom slanted frame in 100th of degrees
 );
 
-SVX_DLLPUBLIC drawinglayer::primitive2d::Primitive2DContainer CreateClippedBorderPrimitives (
-        const Point& rStart, const Point& rEnd, const Style& rBorder,
-        const Rectangle& rClipRect );
-
 /** Draws a horizontal frame border, regards all connected frame styles.
 
     The frame style to draw is passed as parameter rBorder. The function
diff --git a/include/svx/framelinkarray.hxx b/include/svx/framelinkarray.hxx
index 68a335d9503d..83aa8c04a949 100644
--- a/include/svx/framelinkarray.hxx
+++ b/include/svx/framelinkarray.hxx
@@ -331,7 +331,7 @@ public:
     /** Draws the part of the specified range, that is inside the clipping range.
         @param pForceColor
             If not NULL, only this color will be used to draw all frame borders. */
-    void                DrawRange( drawinglayer::processor2d::BaseProcessor2D* rDev,
+    void                DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                             size_t nFirstCol, size_t nFirstRow,
                             size_t nLastCol, size_t nLastRow,
                             const Color* pForceColor = nullptr ) const;
@@ -344,7 +344,10 @@ public:
                             size_t nLastCol, size_t nLastRow ) const;
 
     /** Draws the part of the array, that is inside the clipping range. */
-    void                DrawArray( OutputDevice& rDev ) const;
+    void                DrawArray(OutputDevice& rDev) const;
+
+    /** Draws the part of the array, that is inside the clipping range. */
+    void                DrawArray(drawinglayer::processor2d::BaseProcessor2D& rProcessor) const;
 
 
 private:
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index f5dedb72f36a..b631ac68c176 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -1440,7 +1440,7 @@ void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)
         {
             size_t nRow2 = nRow1;
             while( (nRow2 + 1 <= nLastRow) && pRowInfo[ nRow2 + 1 ].bChanged ) ++nRow2;
-            rArray.DrawRange( pProcessor.get(), nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
+            rArray.DrawRange( *pProcessor.get(), nFirstCol, nRow1, nLastCol, nRow2, pForceColor );
             nRow1 = nRow2 + 1;
         }
     }
@@ -1741,58 +1741,70 @@ void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Co
                         if (aTopLine.Prim() || aTopLine.Secn())
                         {
                             long nUpperRotate = lcl_getRotate( mpDoc, nTab, nX, nY - 1 );
-                            pProcessor->process( svx::frame::CreateBorderPrimitives(
-                                        aPoints[bLayoutRTL?1:0], aPoints[bLayoutRTL?0:1], aTopLine,
-                                        svx::frame::Style(),
-                                        svx::frame::Style(),
-                                        aLeftLine,
-                                        svx::frame::Style(),
-                                        svx::frame::Style(),
-                                        aRightLine,
-                                        pForceColor, nUpperRotate, nAttrRotate ) );
+                            drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                            aSequence.push_back(
+                                svx::frame::CreateBorderPrimitives(
+                                    aPoints[bLayoutRTL?1:0], aPoints[bLayoutRTL?0:1], aTopLine,
+                                    svx::frame::Style(),
+                                    svx::frame::Style(),
+                                    aLeftLine,
+                                    svx::frame::Style(),
+                                    svx::frame::Style(),
+                                    aRightLine,
+                                    pForceColor, nUpperRotate, nAttrRotate ) );
+                            pProcessor->process(aSequence);
                         }
 
                         if (aBottomLine.Prim() || aBottomLine.Secn())
                         {
                             long nLowerRotate = lcl_getRotate( mpDoc, nTab, nX, nY + 1 );
-                            pProcessor->process( svx::frame::CreateBorderPrimitives(
-                                        aPoints[bLayoutRTL?2:3], aPoints[bLayoutRTL?3:2], aBottomLine,
-                                        aLeftLine,
-                                        svx::frame::Style(),
-                                        svx::frame::Style(),
-                                        aRightLine,
-                                        svx::frame::Style(),
-                                        svx::frame::Style(),
-                                        pForceColor, 18000 - nAttrRotate, 18000 - nLowerRotate ) );
+                            drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                            aSequence.push_back(
+                                svx::frame::CreateBorderPrimitives(
+                                    aPoints[bLayoutRTL?2:3], aPoints[bLayoutRTL?3:2], aBottomLine,
+                                    aLeftLine,
+                                    svx::frame::Style(),
+                                    svx::frame::Style(),
+                                    aRightLine,
+                                    svx::frame::Style(),
+                                    svx::frame::Style(),
+                                    pForceColor, 18000 - nAttrRotate, 18000 - nLowerRotate ) );
+                            pProcessor->process(aSequence);
                         }
 
                         // Vertical slanted lines
                         if (aLeftLine.Prim() || aLeftLine.Secn())
                         {
                             long nLeftRotate = lcl_getRotate( mpDoc, nTab, nX - 1, nY );
-                            pProcessor->process( svx::frame::CreateBorderPrimitives(
-                                        aPoints[0], aPoints[3], aLeftLine,
-                                        aTopLine,
-                                        svx::frame::Style(),
-                                        svx::frame::Style(),
-                                        aBottomLine,
-                                        svx::frame::Style(),
-                                        svx::frame::Style(),
-                                        pForceColor, nAttrRotate, nLeftRotate ) );
+                            drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                            aSequence.push_back(
+                                svx::frame::CreateBorderPrimitives(
+                                    aPoints[0], aPoints[3], aLeftLine,
+                                    aTopLine,
+                                    svx::frame::Style(),
+                                    svx::frame::Style(),
+                                    aBottomLine,
+                                    svx::frame::Style(),
+                                    svx::frame::Style(),
+                                    pForceColor, nAttrRotate, nLeftRotate ) );
+                            pProcessor->process(aSequence);
                         }
 
                         if (aRightLine.Prim() || aRightLine.Secn())
                         {
                             long nRightRotate = lcl_getRotate( mpDoc, nTab, nX + 1, nY );
-                            pProcessor->process( svx::frame::CreateBorderPrimitives(
-                                        aPoints[1], aPoints[2], aRightLine,
-                                        svx::frame::Style(),
-                                        svx::frame::Style(),
-                                        aTopLine,
-                                        svx::frame::Style(),
-                                        svx::frame::Style(),
-                                        aBottomLine,
-                                        pForceColor, 18000 - nRightRotate, 18000 - nAttrRotate ) );
+                            drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                            aSequence.push_back(
+                                svx::frame::CreateBorderPrimitives(
+                                    aPoints[1], aPoints[2], aRightLine,
+                                    svx::frame::Style(),
+                                    svx::frame::Style(),
+                                    aTopLine,
+                                    svx::frame::Style(),
+                                    svx::frame::Style(),
+                                    aBottomLine,
+                                    pForceColor, 18000 - nRightRotate, 18000 - nAttrRotate ) );
+                            pProcessor->process(aSequence);
                         }
                     }
                 }
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index 69130024c9d7..ba8b64b806d7 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -33,7 +33,6 @@
 #include <basegfx/polygon/b2dpolygontools.hxx>
 
 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
-#include <drawinglayer/primitive2d/clippedborderlineprimitive2d.hxx>
 
 
 using namespace ::com::sun::star;
@@ -1349,9 +1348,34 @@ bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
 
 // Drawing functions
 
+// get offset to center of line in question
+double lcl_getCenterOfLineOffset(const Style& rBorder, bool bLeftEdge)
+{
+    const bool bPrimUsed(!basegfx::fTools::equalZero(rBorder.Prim())); // left
+    const bool bDistUsed(!basegfx::fTools::equalZero(rBorder.Dist())); // distance
+    const bool bSecnUsed(!basegfx::fTools::equalZero(rBorder.Secn())); // right
+
+    if (bDistUsed || bSecnUsed)
+    {
+        // double line, get center by adding half ditance and half line width.
+        // bLeftEdge defines which line to use
+        return (rBorder.Dist() + (bLeftEdge ? rBorder.Prim() : rBorder.Secn())) * 0.5;
+    }
+    else if (bPrimUsed)
+    {
+        // single line, get center
+        return rBorder.Prim() * 0.5;
+    }
+
+    // no line width at all, stay on unit vector
+    return 0.0;
+}
 
-double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOpposite,
-                      long nAngleSide = 9000, long nAngleOpposite = 9000 )
+double lcl_GetExtent(
+    const Style& rBorder, const Style& rSide, const Style& rOpposite,
+    long nAngleSide, long nAngleOpposite,
+    bool bLeftEdge,     // left or right of rBorder
+    bool bOtherLeft )   // left or right of rSide/rOpposite
 {
     Style aOtherBorder = rSide;
     long nOtherAngle = nAngleSide;
@@ -1370,7 +1394,8 @@ double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOp
 
     // Let's assume the border we are drawing is horizontal and compute all the angles / distances from this
     basegfx::B2DVector aBaseVector( 1.0, 0.0 );
-    basegfx::B2DPoint aBasePoint( 0.0, static_cast<double>( rBorder.GetWidth() / 2 ) );
+    // added support to get the distances to the centers of the line, *not* the outre edge
+    basegfx::B2DPoint aBasePoint(0.0, lcl_getCenterOfLineOffset(rBorder, bLeftEdge));
 
     basegfx::B2DHomMatrix aRotation;
     aRotation.rotate( double( nOtherAngle ) * M_PI / 18000.0 );
@@ -1378,7 +1403,8 @@ double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOp
     basegfx::B2DVector aOtherVector = aRotation * aBaseVector;
     // Compute a line shifted by half the width of the other border
     basegfx::B2DVector aPerpendicular = basegfx::getNormalizedPerpendicular( aOtherVector );
-    basegfx::B2DPoint aOtherPoint = basegfx::B2DPoint() + aPerpendicular * aOtherBorder.GetWidth() / 2;
+    // added support to get the distances to the centers of the line, *not* the outre edge
+    basegfx::B2DPoint aOtherPoint = basegfx::B2DPoint() + aPerpendicular * lcl_getCenterOfLineOffset(aOtherBorder, bOtherLeft);
 
     // Find the cut between the two lines
     double nCut = 0.0;
@@ -1389,67 +1415,32 @@ double lcl_GetExtent( const Style& rBorder, const Style& rSide, const Style& rOp
     return nCut;
 }
 
-basegfx::B2DPoint lcl_PointToB2DPoint( const Point& rPoint )
-{
-    return basegfx::B2DPoint(rPoint.getX(), rPoint.getY());
-}
-
-drawinglayer::primitive2d::Primitive2DContainer CreateClippedBorderPrimitives (
-        const Point& rStart, const Point& rEnd, const Style& rBorder,
-        const Rectangle& rClipRect )
-{
-    drawinglayer::primitive2d::Primitive2DContainer aSequence( 1 );
-    basegfx::B2DPolygon aPolygon;
-    aPolygon.append( lcl_PointToB2DPoint( rClipRect.TopLeft( ) ) );
-    aPolygon.append( lcl_PointToB2DPoint( rClipRect.TopRight( ) ) );
-    aPolygon.append( lcl_PointToB2DPoint( rClipRect.BottomRight( ) ) );
-    aPolygon.append( lcl_PointToB2DPoint( rClipRect.BottomLeft( ) ) );
-    aPolygon.setClosed( true );
-
-    aSequence[0] = new drawinglayer::primitive2d::ClippedBorderLinePrimitive2D(
-        lcl_PointToB2DPoint( rStart ),
-        lcl_PointToB2DPoint( rEnd ),
-        rBorder.Prim(),
-        rBorder.Dist(),
-        rBorder.Secn(),
-        aPolygon,
-        rBorder.GetColorSecn().getBColor(),
-        rBorder.GetColorPrim().getBColor(),
-        rBorder.GetColorGap().getBColor(),
-        rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale() );
-
-    return aSequence;
-}
-
-drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimitives(
+drawinglayer::primitive2d::Primitive2DReference CreateBorderPrimitives(
         const Point& rLPos, const Point& rRPos, const Style& rBorder,
         const DiagStyle& /*rLFromTR*/, const Style& rLFromT, const Style& /*rLFromL*/, const Style& rLFromB, const DiagStyle& /*rLFromBR*/,
         const DiagStyle& /*rRFromTL*/, const Style& rRFromT, const Style& /*rRFromR*/, const Style& rRFromB, const DiagStyle& /*rRFromBL*/,
         const Color* /*pForceColor*/, long nRotateT, long nRotateB )
 {
-    drawinglayer::primitive2d::Primitive2DContainer aSequence( 1 );
-
     basegfx::B2DPoint aStart( rLPos.getX(), rLPos.getY() );
     basegfx::B2DPoint aEnd( rRPos.getX(), rRPos.getY() );
 
-    aSequence[0] = new drawinglayer::primitive2d::BorderLinePrimitive2D(
-        aStart, aEnd,
-        rBorder.Prim(),
-        rBorder.Dist(),
-        rBorder.Secn(),
-        lcl_GetExtent( rBorder, rLFromT, rLFromB, nRotateT, - nRotateB ),
-        lcl_GetExtent( rBorder, rRFromT, rRFromB, 18000 - nRotateT, nRotateB - 18000 ),
-        lcl_GetExtent( rBorder, rLFromB, rLFromT, nRotateB, - nRotateT ),
-        lcl_GetExtent( rBorder, rRFromB, rRFromT, 18000 - nRotateB, nRotateT - 18000 ),
-        rBorder.GetColorSecn().getBColor(),
-        rBorder.GetColorPrim().getBColor(),
-        rBorder.GetColorGap().getBColor(),
-        rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale() );
-
-    return aSequence;
+    return drawinglayer::primitive2d::Primitive2DReference(
+        new drawinglayer::primitive2d::BorderLinePrimitive2D(
+            aStart, aEnd,
+            rBorder.Prim(),
+            rBorder.Dist(),
+            rBorder.Secn(),
+            lcl_GetExtent( rBorder, rLFromT, rLFromB, nRotateT, - nRotateB, true, false ),                  // top-left, so left for rBorder and right for left outer
+            lcl_GetExtent( rBorder, rRFromT, rRFromB, 18000 - nRotateT, nRotateB - 18000, true, true ),     // top-right
+            lcl_GetExtent( rBorder, rLFromB, rLFromT, nRotateB, - nRotateT, false, false ),                 // bottom-left
+            lcl_GetExtent( rBorder, rRFromB, rRFromT, 18000 - nRotateB, nRotateT - 18000, false, true ),    // bottom-right
+            rBorder.GetColorSecn().getBColor(),
+            rBorder.GetColorPrim().getBColor(),
+            rBorder.GetColorGap().getBColor(),
+            rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale()));
 }
 
-drawinglayer::primitive2d::Primitive2DContainer CreateBorderPrimitives(
+drawinglayer::primitive2d::Primitive2DReference CreateBorderPrimitives(
         const Point& rLPos, const Point& rRPos, const Style& rBorder,
         const Style& rLFromT, const Style& rLFromL, const Style& rLFromB,
         const Style& rRFromT, const Style& rRFromR, const Style& rRFromB,
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index 00744c62dcff..3b9c48bfbfdf 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -23,6 +23,7 @@
 #include <vector>
 #include <algorithm>
 #include <vcl/outdev.hxx>
+#include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
 
 namespace svx {
 namespace frame {
@@ -878,7 +879,7 @@ void Array::MirrorSelfX()
 }
 
 // drawing
-void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
+void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
         size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow,
         const Color* pForceColor ) const
 {
@@ -907,23 +908,52 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
                     size_t _nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
 
                     const Style aTlbrStyle = GetCellStyleTLBR( _nFirstCol, _nFirstRow );
-                    if ( aTlbrStyle.GetWidth( ) )
-                        pProcessor->process( CreateClippedBorderPrimitives(
-                                    aRect.TopLeft(), aRect.BottomRight(),
-                                    aTlbrStyle, aRect ) );
+                    if (aTlbrStyle.GetWidth())
+                    {
+                        drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                        aSequence.push_back(
+                            new drawinglayer::primitive2d::BorderLinePrimitive2D(
+                                basegfx::B2DPoint(aRect.Left(), aRect.Top()),
+                                basegfx::B2DPoint(aRect.Right(), aRect.Bottom()),
+                                aTlbrStyle.Prim(),
+                                aTlbrStyle.Dist(),
+                                aTlbrStyle.Secn(),
+                                0.0, 0.0, 0.0, 0.0,
+                                aTlbrStyle.GetColorSecn().getBColor(),
+                                aTlbrStyle.GetColorPrim().getBColor(),
+                                aTlbrStyle.GetColorGap().getBColor(),
+                                aTlbrStyle.UseGapColor(),
+                                aTlbrStyle.Type(),
+                                aTlbrStyle.PatternScale()));
+                        rProcessor.process(aSequence);
+                    }
 
                     const Style aBltrStyle = GetCellStyleBLTR( _nFirstCol, _nFirstRow );
-                    if ( aBltrStyle.GetWidth( ) )
-                        pProcessor->process( CreateClippedBorderPrimitives(
-                                    aRect.BottomLeft(), aRect.TopRight(),
-                                    aBltrStyle, aRect ) );
+                    if (aBltrStyle.GetWidth())
+                    {
+                        drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                        aSequence.push_back(
+                            new drawinglayer::primitive2d::BorderLinePrimitive2D(
+                                basegfx::B2DPoint(aRect.Left(), aRect.Bottom()),
+                                basegfx::B2DPoint(aRect.Right(), aRect.Top()),
+                                aBltrStyle.Prim(),
+                                aBltrStyle.Dist(),
+                                aBltrStyle.Secn(),
+                                0.0, 0.0, 0.0, 0.0,
+                                aBltrStyle.GetColorSecn().getBColor(),
+                                aBltrStyle.GetColorPrim().getBColor(),
+                                aBltrStyle.GetColorGap().getBColor(),
+                                aBltrStyle.UseGapColor(),
+                                aBltrStyle.Type(),
+                                aBltrStyle.PatternScale()));
+                        rProcessor.process(aSequence);
+                    }
                 }
             }
         }
     }
 
     // *** horizontal frame borders ***
-
     for( nRow = nFirstRow; nRow <= nLastRow + 1; ++nRow )
     {
         double fAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow );
@@ -970,10 +1000,27 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
             {
                 // draw previous frame border
                 Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
-                if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) )
-                   pProcessor->process( CreateBorderPrimitives( aStartPos, aEndPos, *pStart,
-                        aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR,
-                        aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor ) );
+                if (pStart->Prim() && (aStartPos.X() <= aEndPos.X()))
+                {
+                    drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                    aSequence.push_back(
+                        CreateBorderPrimitives(
+                            aStartPos,
+                            aEndPos,
+                            *pStart,
+                            aStartLFromTR,
+                            *pStartLFromT,
+                            *pStartLFromL,
+                            *pStartLFromB,
+                            aStartLFromBR,
+                            aEndRFromTL,
+                            *pEndRFromT,
+                            *pEndRFromR,
+                            *pEndRFromB,
+                            aEndRFromBL,
+                            pForceColor));
+                    rProcessor.process(aSequence);
+                }
 
                 // re-init "*Start***" variables
                 aStartPos = aEndPos;
@@ -995,10 +1042,27 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
 
         // draw last frame border
         Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
-        if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) )
-            pProcessor->process( CreateBorderPrimitives( aStartPos, aEndPos, *pStart,
-                aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR,
-                aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL, pForceColor ) );
+        if (pStart->Prim() && (aStartPos.X() <= aEndPos.X()))
+        {
+            drawinglayer::primitive2d::Primitive2DContainer aSequence;
+            aSequence.push_back(
+                CreateBorderPrimitives(
+                    aStartPos,
+                    aEndPos,
+                    *pStart,
+                    aStartLFromTR,
+                    *pStartLFromT,
+                    *pStartLFromL,
+                    *pStartLFromB,
+                    aStartLFromBR,
+                    aEndRFromTL,
+                    *pEndRFromT,
+                    *pEndRFromR,
+                    *pEndRFromB,
+                    aEndRFromBL,
+                    pForceColor));
+            rProcessor.process(aSequence);
+        }
     }
 
     // *** vertical frame borders ***
@@ -1048,10 +1112,35 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
             {
                 // draw previous frame border
                 Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
-                if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) )
-                    pProcessor->process( CreateBorderPrimitives( aEndPos, aStartPos, *pStart,
-                        aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR,
-                        aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR, pForceColor ) );
+                if (pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()))
+                {
+                    drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                    aSequence.push_back(
+                        CreateBorderPrimitives(
+                            // This replaces DrawVerFrameBorder which went from top to bottom. To be able to use
+                            // the same method as for horizontal (CreateBorderPrimitives), the given borders
+                            // have to be rearranged. Best is to look at the explanations of parameters in
+                            // framelink.hxx and the former calls to DrawVerFrameBorder and it's parameters.
+                            // In principle, the order of the five TFrom and BFrom has to be
+                            // inverted to get the same orientation. Before, EndPos and StartPos were changed
+                            // which avoids the reordering, but also leads to inverted line patters for vertical
+                            // lines
+                            aStartPos,
+                            aEndPos,
+                            *pStart,
+                            aStartTFromBR,
+                            *pStartTFromR,
+                            *pStartTFromT,
+                            *pStartTFromL,
+                            aStartTFromBL,
+                            aEndBFromTR,
+                            *pEndBFromR,
+                            *pEndBFromB,
+                            *pEndBFromL,
+                            aEndBFromTL,
+                            pForceColor));
+                    rProcessor.process(aSequence);
+                }
 
                 // re-init "*Start***" variables
                 aStartPos = aEndPos;
@@ -1073,10 +1162,28 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D* pProcessor,
 
         // draw last frame border
         Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
-        if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) )
-            pProcessor->process( CreateBorderPrimitives( aEndPos, aStartPos, *pStart,
-                aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR,
-                aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR, pForceColor ) );
+        if (pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()))
+        {
+            drawinglayer::primitive2d::Primitive2DContainer aSequence;
+            aSequence.push_back(
+                CreateBorderPrimitives(
+                    // also reordered, see call to CreateBorderPrimitives above
+                    aStartPos,
+                    aEndPos,
+                    *pStart,
+                    aStartTFromBR,
+                    *pStartTFromR,
+                    *pStartTFromT,
+                    *pStartTFromL,
+                    aStartTFromBL,
+                    aEndBFromTR,
+                    *pEndBFromR,
+                    *pEndBFromB,
+                    *pEndBFromL,
+                    aEndBFromTL,
+                    pForceColor));
+            rProcessor.process(aSequence);
+        }
     }
 }
 
@@ -1291,6 +1398,12 @@ void Array::DrawArray( OutputDevice& rDev ) const
         DrawRange( rDev, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1 );
 }
 
+void Array::DrawArray(drawinglayer::processor2d::BaseProcessor2D& rProcessor) const
+{
+    if (mxImpl->mnWidth && mxImpl->mnHeight)
+        DrawRange(rProcessor, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, nullptr);
+}
+
 
 #undef ORIGCELL
 #undef CELLACC
diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx
index 7777e896682d..460e3c42eb1a 100644
--- a/svx/source/dialog/frmsel.cxx
+++ b/svx/source/dialog/frmsel.cxx
@@ -28,6 +28,7 @@
 #include <com/sun/star/accessibility/AccessibleEventId.hpp>
 #include <com/sun/star/accessibility/AccessibleStateType.hpp>
 #include <vcl/settings.hxx>
+#include <drawinglayer/processor2d/processor2dtools.hxx>
 
 #include <svx/dialogs.hrc>
 #include "frmsel.hrc"
@@ -656,7 +657,36 @@ void FrameSelectorImpl::DrawAllFrameBorders()
             maArray.SetCellStyleDiag( nCol, nRow, maTLBR.GetUIStyle(), maBLTR.GetUIStyle() );
 
     // Let the helper array draw itself
-    maArray.DrawArray( *mpVirDev.get() );
+    static bool bUsePrimitives(true);
+
+    if (bUsePrimitives)
+    {
+        // This is used in the dialog/control for 'Border' attributes. When using
+        // the original paint below instead of primitives, the advantage currently
+        // is the correct visualization of diagonal line(s) including overlaying,
+        // but the rest is bad. Since the edit views use primitives and the preview
+        // should be 'real' I opt for also changing this to primitives. I will
+        // keep the old solution and add a switch (above) based on a static bool so
+        // that interested people may test this out in the debugger.
+        // This is one more hint to enhance the primitive visualization further to
+        // support diagonals better - that's the way to go.
+        const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
+        std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
+            drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
+                *mpVirDev.get(),
+                aNewViewInformation2D));
+
+        if (pProcessor2D)
+        {
+            maArray.DrawArray(*pProcessor2D.get());
+            pProcessor2D.reset();
+        }
+    }
+    else
+    {
+        // original paint
+        maArray.DrawArray(*mpVirDev.get());
+    }
 }
 
 void FrameSelectorImpl::DrawVirtualDevice()
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index b973507a21ea..c24450ad034c 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2744,33 +2744,37 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
 
             if (bHori)
             {
-                mrTabFrame.ProcessPrimitives( svx::frame::CreateBorderPrimitives(
-                    aPaintStart,
-                    aPaintEnd,
-                    aStyles[ 0 ],   // current style
-                    aStyles[ 1 ],   // aLFromT
-                    aStyles[ 2 ],   // aLFromL
-                    aStyles[ 3 ],   // aLFromB
-                    aStyles[ 4 ],   // aRFromT
-                    aStyles[ 5 ],   // aRFromR
-                    aStyles[ 6 ],   // aRFromB
-                    pTmpColor)
-                );
+                drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                aSequence.push_back(
+                    svx::frame::CreateBorderPrimitives(
+                        aPaintStart,
+                        aPaintEnd,
+                        aStyles[ 0 ],   // current style
+                        aStyles[ 1 ],   // aLFromT
+                        aStyles[ 2 ],   // aLFromL
+                        aStyles[ 3 ],   // aLFromB
+                        aStyles[ 4 ],   // aRFromT
+                        aStyles[ 5 ],   // aRFromR
+                        aStyles[ 6 ],   // aRFromB
+                        pTmpColor));
+                mrTabFrame.ProcessPrimitives(aSequence);
             }
             else
             {
-                mrTabFrame.ProcessPrimitives( svx::frame::CreateBorderPrimitives(
-                    aPaintEnd,
-                    aPaintStart,
-                    aStyles[ 0 ],   // current style
-                    aStyles[ 4 ],   // aBFromL
-                    aStyles[ 5 ],   // aBFromB
-                    aStyles[ 6 ],   // aBFromR
-                    aStyles[ 1 ],   // aTFromL
-                    aStyles[ 2 ],   // aTFromT
-                    aStyles[ 3 ],   // aTFromR
-                    pTmpColor)
-                );
+                drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                aSequence.push_back(
+                    svx::frame::CreateBorderPrimitives(
+                        aPaintEnd,
+                        aPaintStart,
+                        aStyles[ 0 ],   // current style
+                        aStyles[ 4 ],   // aBFromL
+                        aStyles[ 5 ],   // aBFromB
+                        aStyles[ 6 ],   // aBFromR
+                        aStyles[ 1 ],   // aTFromL
+                        aStyles[ 2 ],   // aTFromT
+                        aStyles[ 3 ],   // aTFromR
+                        pTmpColor));
+                mrTabFrame.ProcessPrimitives(aSequence);
             }
         }
 


More information about the Libreoffice-commits mailing list