borderline: corrections for calc and writer

Made corrections/finetuning for Calc and Writer.
Had to remove some former code which tried to do
corrections.

Change-Id: Id9fc687b9a709d250faaad76c37ecfda8d8feb9b
diff --git a/drawinglayer/qa/unit/border.cxx b/drawinglayer/qa/unit/border.cxx
index ce99965..326c5de 100644
--- a/drawinglayer/qa/unit/border.cxx
+++ b/drawinglayer/qa/unit/border.cxx
@@ -61,7 +61,15 @@ void DrawinglayerBorderTest::testDoubleDecompositionSolid()
    basegfx::BColor aColorGap;
    bool const bHasGapColor = false;
    SvxBorderLineStyle const nStyle = SvxBorderLineStyle::DOUBLE;
    rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> aBorder(new drawinglayer::primitive2d::BorderLinePrimitive2D(aStart, aEnd, fLeftWidth, fDistance, fRightWidth, fExtendLeftStart, fExtendLeftEnd, fExtendRightStart, fExtendRightEnd, aColorRight, aColorLeft, aColorGap, bHasGapColor, nStyle));
    rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> aBorder(
        new drawinglayer::primitive2d::BorderLinePrimitive2D(
            aStart,
            aEnd,
            drawinglayer::primitive2d::BorderLine(fLeftWidth, aColorLeft, fExtendLeftStart, fExtendLeftEnd),
            drawinglayer::primitive2d::BorderLine(fDistance, aColorGap),
            drawinglayer::primitive2d::BorderLine(fRightWidth, aColorRight, fExtendRightStart, fExtendRightEnd),
            bHasGapColor,
            nStyle));

    // Decompose it into polygons.
    drawinglayer::geometry::ViewInformation2D aView;
@@ -109,7 +117,16 @@ void DrawinglayerBorderTest::testDoublePixelProcessing()
    basegfx::BColor aColorGap;
    bool const bHasGapColor = false;
    SvxBorderLineStyle const nStyle = SvxBorderLineStyle::DOUBLE;
    rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> xBorder(new drawinglayer::primitive2d::BorderLinePrimitive2D(aStart, aEnd, fLeftWidth, fDistance, fRightWidth, fExtendLeftStart, fExtendLeftEnd, fExtendRightStart, fExtendRightEnd, aColorRight, aColorLeft, aColorGap, bHasGapColor, nStyle));
    rtl::Reference<drawinglayer::primitive2d::BorderLinePrimitive2D> xBorder(
        new drawinglayer::primitive2d::BorderLinePrimitive2D(
            aStart,
            aEnd,
            drawinglayer::primitive2d::BorderLine(fLeftWidth, aColorLeft, fExtendLeftStart, fExtendLeftEnd),
            drawinglayer::primitive2d::BorderLine(fDistance, aColorGap),
            drawinglayer::primitive2d::BorderLine(fRightWidth, aColorRight, fExtendRightStart, fExtendRightEnd),
            bHasGapColor,
            nStyle));

    drawinglayer::primitive2d::Primitive2DContainer aPrimitives;
    aPrimitives.push_back(drawinglayer::primitive2d::Primitive2DReference(xBorder.get()));

diff --git a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
index 724ba87..dae52a2 100644
--- a/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
+++ b/drawinglayer/source/primitive2d/borderlineprimitive2d.cxx
@@ -49,6 +49,10 @@ namespace drawinglayer
        {
        }

        BorderLine::~BorderLine()
        {
        }

        bool BorderLine::operator==(const BorderLine& rBorderLine) const
        {
            return getWidth() == rBorderLine.getWidth()
@@ -104,13 +108,17 @@ namespace drawinglayer
                    // double line with gap. Use mfDiscreteGapDistance (see get2DDecomposition) as distance.
                    // That value is prepared to be at least one pixel (discrete unit) so that the
                    // decomposition is view-dependent in this cases
                    const BorderLine& rLeft(getBorderLines()[0]);
                    const BorderLine& rGap(getBorderLines()[1]);
                    const BorderLine& rRight(getBorderLines()[2]);
                    const double fFullWidth(rLeft.getWidth() + mfDiscreteGapDistance + rRight.getWidth());

                    {
                        // inside line (left of vector). Create stroke primitive centered on line width
                        const BorderLine& rLeft(getBorderLines()[0]);
                        const double fDeltaY((mfDiscreteGapDistance + rLeft.getWidth()) * 0.5);
                        // inside line (left of vector). Create stroke primitive centered on left line width
                        const double fDeltaY((rLeft.getWidth() - fFullWidth) * 0.5);
                        const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
                        const basegfx::B2DPoint aStart(getStart() - (aVector * rLeft.getExtendStart()) - aDeltaY);
                        const basegfx::B2DPoint aEnd(getEnd() + (aVector * rLeft.getExtendEnd()) - aDeltaY);
                        const basegfx::B2DPoint aStart(getStart() - (aVector * rLeft.getExtendStart()) + aDeltaY);
                        const basegfx::B2DPoint aEnd(getEnd() + (aVector * rLeft.getExtendEnd()) + aDeltaY);
                        const attribute::LineAttribute aLineAttribute(rLeft.getRGBColor(), rLeft.getWidth());

                        addPolygonStrokePrimitive2D(
@@ -124,10 +132,11 @@ namespace drawinglayer
                    if (hasGapColor())
                    {
                        // gap (if visible, found practical usage in Writer MultiColorBorderLines).
                        // Create stroke primitive on vector with given color
                        const BorderLine& rGap(getBorderLines()[1]);
                        const basegfx::B2DPoint aStart(getStart() - (aVector * rGap.getExtendStart()));
                        const basegfx::B2DPoint aEnd(getEnd() + (aVector * rGap.getExtendEnd()));
                        // Create stroke primitive on vector with given color centered on gap position
                        const double fDeltaY(((fFullWidth - mfDiscreteGapDistance) * 0.5) - rRight.getWidth());
                        const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
                        const basegfx::B2DPoint aStart(getStart() - (aVector * rGap.getExtendStart()) + aDeltaY);
                        const basegfx::B2DPoint aEnd(getEnd() + (aVector * rGap.getExtendEnd()) + aDeltaY);
                        const attribute::LineAttribute aLineAttribute(rGap.getRGBColor(), mfDiscreteGapDistance);

                        addPolygonStrokePrimitive2D(
@@ -139,9 +148,8 @@ namespace drawinglayer
                    }

                    {
                        // outside line (right of vector). Create stroke primitive centered on line width
                        const BorderLine& rRight(getBorderLines()[2]);
                        const double fDeltaY((mfDiscreteGapDistance + rRight.getWidth()) * 0.5);
                        // outside line (right of vector). Create stroke primitive centered on right line width
                        const double fDeltaY((fFullWidth - rRight.getWidth()) * 0.5);
                        const basegfx::B2DVector aDeltaY(aPerpendicular * fDeltaY);
                        const basegfx::B2DPoint aStart(getStart() - (aVector * rRight.getExtendStart()) + aDeltaY);
                        const basegfx::B2DPoint aEnd(getEnd() + (aVector * rRight.getExtendEnd()) + aDeltaY);
diff --git a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
index 3108a81..a174dcb9d 100644
--- a/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
+++ b/include/drawinglayer/primitive2d/borderlineprimitive2d.hxx
@@ -58,6 +58,7 @@ namespace drawinglayer
                const basegfx::BColor& rRGBColor,
                double fExtendStart = 0.0,
                double fExtendEnd = 0.0);
            virtual ~BorderLine();

            double getWidth() const { return mfWidth; }
            const basegfx::BColor& getRGBColor() const { return maRGBColor; }
diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx
index 5345b69..acc7ec25 100644
--- a/sc/source/ui/inc/output.hxx
+++ b/sc/source/ui/inc/output.hxx
@@ -231,7 +231,7 @@ private:

    double          GetStretch();

    void            DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Color* pForceColor);       // pixel
    void            DrawRotatedFrame(vcl::RenderContext& rRenderContext);       // pixel

    drawinglayer::processor2d::BaseProcessor2D*  CreateProcessor2D( );

diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index f4db5fe..87e495f 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -1387,7 +1387,7 @@ void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)

    if (mrTabInfo.maArray.HasCellRotation())
    {
        DrawRotatedFrame(rRenderContext, pForceColor);        // removes the lines that must not be painted here
        DrawRotatedFrame(rRenderContext);        // removes the lines that must not be painted here
    }

    long nInitPosX = nScrX;
@@ -1474,74 +1474,7 @@ void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)
    rRenderContext.SetDrawMode(nOldDrawMode);
}

// Line below the cell

static const ::editeng::SvxBorderLine* lcl_FindHorLine( ScDocument* pDoc,
                        SCCOL nCol, SCROW nRow, SCTAB nTab, ScRotateDir nRotDir,
                        bool bTopLine )
{
    if ( nRotDir != ScRotateDir::Left && nRotDir != ScRotateDir::Right )
        return nullptr;

    bool bFound = false;
    while (!bFound)
    {
        if ( nRotDir == ScRotateDir::Left )
        {
            // text to the left -> line from the right
            if ( nCol < MAXCOL )
                ++nCol;
            else
                return nullptr; // couldn't find it
        }
        else
        {
            // text to the right -> line from the left
            if ( nCol > 0 )
                --nCol;
            else
                return nullptr; // couldn't find it
        }
        const ScPatternAttr* pPattern = pDoc->GetPattern( nCol, nRow, nTab );
        const SfxItemSet* pCondSet = pDoc->GetCondResult( nCol, nRow, nTab );
        if ( !pPattern->GetRotateVal( pCondSet ) ||
                static_cast<const SvxRotateModeItem&>(pPattern->GetItem(
                    ATTR_ROTATE_MODE, pCondSet)).GetValue() == SVX_ROTATE_MODE_STANDARD )
            bFound = true;
    }

    if (bTopLine)
        --nRow;
    const ::editeng::SvxBorderLine* pThisBottom;
    if ( ValidRow(nRow) )
        pThisBottom = static_cast<const SvxBoxItem*>(pDoc->GetAttr( nCol, nRow, nTab, ATTR_BORDER ))->GetBottom();
    else
        pThisBottom = nullptr;
    const ::editeng::SvxBorderLine* pNextTop;
    if ( nRow < MAXROW )
        pNextTop = static_cast<const SvxBoxItem*>(pDoc->GetAttr( nCol, nRow+1, nTab, ATTR_BORDER ))->GetTop();
    else
        pNextTop = nullptr;

    if ( ScHasPriority( pThisBottom, pNextTop ) )
        return pThisBottom;
    else
        return pNextTop;
}

static long lcl_getRotate( ScDocument* pDoc, SCTAB nTab, SCCOL nX, SCROW nY )
{
    long nRotate = 0;

    const ScPatternAttr* pPattern = pDoc->GetPattern( nX, nY, nTab );
    const SfxItemSet* pCondSet = pDoc->GetCondResult( nX, nY, nTab );

    nRotate = pPattern->GetRotateVal( pCondSet );

    return nRotate;
}

void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Color* pForceColor)
void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext)
{
    //! save nRotMax
    SCCOL nRotMax = nX2;
@@ -1555,8 +1488,6 @@ void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Co
    const StyleSettings& rStyleSettings = Application::GetSettings().GetStyleSettings();
    bool bCellContrast = mbUseStyleColor && rStyleSettings.GetHighContrastMode();

    // color (pForceColor) is determined externally, including DrawMode changes

    long nInitPosX = nScrX;
    if ( bLayoutRTL )
    {
@@ -1575,9 +1506,7 @@ void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Co
    else
        rRenderContext.SetClipRegion( vcl::Region( aClipRect ) );

    svx::frame::Array& rArray = mrTabInfo.maArray;
    std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor(CreateProcessor2D( ));

    long nPosY = nScrY;
    for (SCSIZE nArrY=1; nArrY<nArrCount; nArrY++)
    {
@@ -1587,8 +1516,6 @@ void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Co
        RowInfo& rThisRowInfo = pRowInfo[nArrY];
        RowInfo& rNextRowInfo = pRowInfo[nArrY+1];

        size_t nRow = static_cast< size_t >( nArrY );

        long nRowHeight = rThisRowInfo.nHeight;
        if ( rThisRowInfo.nRotMaxCol != SC_ROTMAX_NONE &&
             ( rThisRowInfo.bChanged || rPrevRowInfo.bChanged ||
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index c746e88..9bb3830 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -278,73 +278,6 @@ 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 distance 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, long nAngleOpposite,
    bool bLeftEdge,     // left or right of rBorder
    bool bOtherLeft )   // left or right of rSide/rOpposite
{
    Style aOtherBorder = rSide;
    long nOtherAngle = nAngleSide;
    if ( rSide.GetWidth() == 0 && rOpposite.GetWidth() > 0 )
    {
        nOtherAngle = nAngleOpposite;
        aOtherBorder = rOpposite;
    }
    else if ( rSide.GetWidth() == 0 && rOpposite.GetWidth() == 0 )
    {
        if ( ( nAngleOpposite % 18000 ) == 0 )
            nOtherAngle = nAngleSide;
        else if ( ( nAngleSide % 18000 ) == 0 )
            nOtherAngle = nAngleOpposite;
    }

    // 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 );
    // 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 );

    basegfx::B2DVector aOtherVector = aRotation * aBaseVector;
    // Compute a line shifted by half the width of the other border
    basegfx::B2DVector aPerpendicular = basegfx::getNormalizedPerpendicular( aOtherVector );
    // 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;
    basegfx::tools::findCut(
            aBasePoint, aBaseVector, aOtherPoint, aOtherVector,
            CutFlagValue::ALL, &nCut );

    return nCut;
}

struct OffsetPair
{
    double          mfLeft;
@@ -523,7 +456,14 @@ double getSimpleExtendedLineValues(

    if (pResult)
    {
        return (pResult->mfLeftRight + pResult->mfRightRight) * 0.5 * (bEdgeStart ? -fLength : fLength);
        if (bEdgeStart)
        {
            return (pResult->mfLeftRight + pResult->mfRightRight) * -0.5 * fLength;
        }
        else
        {
            return (pResult->mfLeftLeft + pResult->mfRightLeft) * 0.5 * fLength;
        }
    }

    return 0.0;
@@ -552,8 +492,17 @@ double getComplexExtendedLineValues(

    if (pResult)
    {
        return (pResult->mfLeftRight + pResult->mfRightRight) * 0.5 * (bEdgeStart ? -fLength : fLength);
        if (bEdgeStart)
        {
            return (pResult->mfLeftRight + pResult->mfRightRight) * 0.5 * -fLength;
        }
        else
        {
            return (pResult->mfLeftLeft + pResult->mfRightLeft) * 0.5 * fLength;
        }
    }

    return 0.0;
}

void CreateBorderPrimitives(
@@ -636,7 +585,10 @@ void CreateBorderPrimitives(
        else if (2 == myOffsets.size())
        {
            // we are a double edge, calculate cuts with edges coming from above/below
            // for both edges to detect the line start/end extensions
            // for both edges to detect the line start/end extensions. In the furure this
            // needs to be extended to use two values per extension, getComplexExtendedLineValues
            // internally prepares these already. drawinglayer::primitive2d::BorderLine will
            // then need to take these double entries (maybe a pair) and use them internally.
            double mfExtendLeftStart(0.0);
            double mfExtendLeftEnd(0.0);
            double mfExtendRightStart(0.0);
@@ -671,8 +623,12 @@ void CreateBorderPrimitives(
                        drawinglayer::primitive2d::BorderLine(
                            rBorder.Dist(),
                            (pForceColor ? *pForceColor : rBorder.GetColorGap()).getBColor(),
                            (mfExtendLeftStart + mfExtendRightStart) * 0.5,
                            (mfExtendLeftEnd + mfExtendRightEnd) * 0.5),
                            // needs to be determined in detail later, for now use the max prolongation
                            // from left/right, butz do not less than half (0.0). This works decently,
                            // but not perfect (see Writer, use three-color-style, look at upper/lower#
                            // connections)
                            std::max(0.0, std::max(mfExtendLeftStart, mfExtendRightStart)),
                            std::max(0.0, std::max(mfExtendLeftEnd, mfExtendRightEnd))),
                        drawinglayer::primitive2d::BorderLine(
                            rBorder.Secn(),
                            (pForceColor ? *pForceColor : rBorder.GetColorSecn()).getBColor(),
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index 839e9be..04d0d2a 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -132,8 +132,6 @@ void lclSetMergedRange( CellVec& rCells, size_t nWidth, size_t nFirstCol, size_t
static const Style OBJ_STYLE_NONE;
static const Cell OBJ_CELL_NONE;

const bool DIAG_DBL_CLIP_DEFAULT = false;

struct ArrayImpl
{
    CellVec             maCells;
@@ -1122,7 +1120,7 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                        aY.normalize();
                    }

                    drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                    drawinglayer::primitive2d::Primitive2DContainer aSequence;
                    CreateBorderPrimitives(
                        aSequence,
                        aOrigin,
@@ -1188,7 +1186,7 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                aY.normalize();
            }

            drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
            drawinglayer::primitive2d::Primitive2DContainer aSequence;
            CreateBorderPrimitives(
                aSequence,
                aOrigin,
@@ -1288,7 +1286,7 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                        aY = -aY;
                    }

                    drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                    drawinglayer::primitive2d::Primitive2DContainer aSequence;
                    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
@@ -1367,7 +1365,7 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                aY = -aY;
            }

            drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
            drawinglayer::primitive2d::Primitive2DContainer aSequence;
            CreateBorderPrimitives(
                // also reordered, see call to CreateBorderPrimitives above
                aSequence,
diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx
index 9356785..e3ccf03 100644
--- a/svx/source/dialog/frmsel.cxx
+++ b/svx/source/dialog/frmsel.cxx
@@ -667,9 +667,6 @@ void FrameSelectorImpl::DrawAllFrameBorders()
        for( size_t nRow = 0; nRow < maArray.GetRowCount(); ++nRow )
            maArray.SetCellStyleDiag( nCol, nRow, maTLBR.GetUIStyle(), maBLTR.GetUIStyle() );

    // Let the helper array draw itself
    static bool bUsePrimitives(true);

    // 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,
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index 407ac44..493eb8e 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2448,11 +2448,6 @@ struct SwLineEntry
    SwTwips mnKey;
    SwTwips mnStartPos;
    SwTwips mnEndPos;
    SwTwips mnOffset;

    bool mbOffsetPerp;
    bool mbOffsetStart;
    bool mbOffsetEnd;

    svx::frame::Style maAttribute;

@@ -2474,10 +2469,6 @@ SwLineEntry::SwLineEntry( SwTwips nKey,
    :   mnKey( nKey ),
        mnStartPos( nStartPos ),
        mnEndPos( nEndPos ),
        mnOffset( 0 ),
        mbOffsetPerp(false),
        mbOffsetStart(false),
        mbOffsetEnd(false),
        maAttribute( rAttribute )
{
}
@@ -2556,8 +2547,6 @@ class SwTabFramePainter
                            svx::frame::Style*,
                            bool bHori ) const;

    void AdjustTopLeftFrames();

public:
    explicit SwTabFramePainter( const SwTabFrame& rTabFrame );

@@ -2568,7 +2557,6 @@ SwTabFramePainter::SwTabFramePainter( const SwTabFrame& rTabFrame )
    : mrTabFrame( rTabFrame )
{
    HandleFrame( rTabFrame );
    AdjustTopLeftFrames();
}

void SwTabFramePainter::HandleFrame( const SwLayoutFrame& rLayoutFrame )
@@ -2666,42 +2654,6 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
            svx::frame::Style aStyles[ 7 ];
            aStyles[ 0 ] = rEntryStyle;
            FindStylesForLine( aStart, aEnd, aStyles, bHori );

            // Account for double line thicknesses for the top- and left-most borders.
            if (rEntry.mnOffset)
            {
                if (bHori)
                {
                    if (rEntry.mbOffsetPerp)
                    {
                        // Apply offset in perpendicular direction.
                        aStart.Y() -= rEntry.mnOffset;
                        aEnd.Y() -= rEntry.mnOffset;
                    }
                    if (rEntry.mbOffsetStart)
                        // Apply offset at the start of a border.
                        aStart.X() -= rEntry.mnOffset;
                    if (rEntry.mbOffsetEnd)
                        // Apply offset at the end of a border.
                        aEnd.X() += rEntry.mnOffset;
                }
                else
                {
                    if (rEntry.mbOffsetPerp)
                    {
                        // Apply offset in perpendicular direction.
                        aStart.X() -= rEntry.mnOffset;
                        aEnd.X() -= rEntry.mnOffset;
                    }
                    if (rEntry.mbOffsetStart)
                        // Apply offset at the start of a border.
                        aStart.Y() -= rEntry.mnOffset;
                    if (rEntry.mbOffsetEnd)
                        // Apply offset at the end of a border.
                        aEnd.Y() += rEntry.mnOffset;
                }
            }

            SwRect aRepaintRect( aStart, aEnd );

            // the repaint rectangle has to be moved a bit for the centered lines:
@@ -2769,47 +2721,25 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                    aPaintEnd.Y() = aUpperAligned.Bottom_();
            }

            // logically vertical lines are painted centered on the line,
            // logically horizontal lines are painted "below" the line
            //
            // This does not need to be done here, it is set in SwTabFramePainter::Insert
            // already using SetRefMode(...) as property of the BorderLine Style, see there.
            // When additionally adding the offset here manually, it will be applied
            // double and will be rendered wrong. This did not happen before because
            // the setting of the svx::frame::RefMode at svx::frame::Style was ignored there.
            //
            // bool const isBelow((mrTabFrame.IsVertical()) ? !bHori : bHori);
            // double const offsetStart = (isBelow)
            //     ?   aStyles[0].GetWidth() / 2.0
            //     :   std::max<double>(aStyles[1].GetWidth(),
            //             aStyles[3].GetWidth()) / 2.0;
            // double const offsetEnd = (isBelow)
            //     ?   aStyles[0].GetWidth() / 2.0
            //     :   std::max<double>(aStyles[4].GetWidth(),
            //             aStyles[6].GetWidth()) / 2.0;
            // if (mrTabFrame.IsVertical())
            // {
            //     aPaintStart.X() -= static_cast<long>(offsetStart + 0.5);
            //     aPaintEnd.X()   -= static_cast<long>(offsetEnd   + 0.5);
            // }
            // else
            // {
            //     aPaintStart.Y() += static_cast<long>(offsetStart + 0.5);
            //     aPaintEnd.Y()   += static_cast<long>(offsetEnd   + 0.5);
            // }

            if (bHori)
            {
                const basegfx::B2DPoint aOrigin(aPaintStart.X(), aPaintStart.Y());
                const basegfx::B2DVector aX(basegfx::B2DPoint(aPaintEnd.X(), aPaintEnd.Y()) - aOrigin);
                const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(aX));
                drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                drawinglayer::primitive2d::Primitive2DContainer aSequence;

                svx::frame::CreateBorderPrimitives(
                    aSequence,
                    aOrigin,
                    aX,
                    aY,

                    // Writer creates it's vertical BorderLines bottom-to-top (see below).
                    // To make the horizontal lines correctly 'guess' the line extensions
                    // for the then mirrored svx::frame::Style for irregular double lines,
                    // hand over the for that case correct orientatoin of the 'other'
                    // incoming edges
                    -aY,

                    aStyles[ 0 ],   // current style
                    aStyles[ 1 ],   // aLFromT
                    aStyles[ 2 ],   // aLFromL
@@ -2825,7 +2755,7 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
                const basegfx::B2DPoint aOrigin(aPaintEnd.X(), aPaintEnd.Y());
                const basegfx::B2DVector aX(basegfx::B2DPoint(aPaintStart.X(), aPaintStart.Y()) - aOrigin);
                const basegfx::B2DVector aY(basegfx::getNormalizedPerpendicular(aX));
                drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                drawinglayer::primitive2d::Primitive2DContainer aSequence;

                svx::frame::CreateBorderPrimitives(
                    aSequence,
@@ -2954,58 +2884,6 @@ void SwTabFramePainter::FindStylesForLine( const Point& rStartPoint,
    }
}

namespace {

void calcOffsetForDoubleLine( SwLineEntryMap& rLines )
{
    SwLineEntryMap aNewLines;
    SwLineEntryMap::iterator it = rLines.begin(), itEnd = rLines.end();
    bool bFirst = true;
    for (; it != itEnd; ++it)
    {
        if (bFirst)
        {
            // First line needs to be offset to account for double line thickness.
            SwLineEntrySet aNewSet;
            const SwLineEntrySet& rSet = it->second;
            SwLineEntrySet::iterator itSet = rSet.begin(), itSetEnd = rSet.end();
            size_t nEntryCount = rSet.size();
            for (size_t i = 0; itSet != itSetEnd; ++itSet, ++i)
            {
                SwLineEntry aLine = *itSet;
                if (aLine.maAttribute.Secn())
                {
                    // Apply offset only for double lines.
                    aLine.mnOffset = static_cast<SwTwips>(aLine.maAttribute.Dist());
                    aLine.mbOffsetPerp = true;

                    if (i == 0)
                        aLine.mbOffsetStart = true;
                    if (i == nEntryCount - 1)
                        aLine.mbOffsetEnd = true;
                }

                aNewSet.insert(aLine);
            }

            aNewLines.insert(SwLineEntryMap::value_type(it->first, aNewSet));
        }
        else
            aNewLines.insert(SwLineEntryMap::value_type(it->first, it->second));

        bFirst = false;
    }
    rLines.swap(aNewLines);
}

}

void SwTabFramePainter::AdjustTopLeftFrames()
{
    calcOffsetForDoubleLine(maHoriLines);
    calcOffsetForDoubleLine(maVertLines);
}

/**
 * Special case: #i9860#
 * first line in follow table without repeated headlines