tdf#126269 Handle diagonal borderline better for merged cells

Change-Id: I04776bbd237dc1fa881385bfe9be7f034b58e35a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127431
Tested-by: Jenkins
Reviewed-by: Armin Le Grand <Armin.Le.Grand@me.com>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/127591
Reviewed-by: Thorsten Behrens <thorsten.behrens@allotropia.de>
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index 6c06c30..7419b1b 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -225,6 +225,8 @@ struct ArrayImpl
    bool                IsColInClipRange( size_t nCol ) const;
    bool                IsRowInClipRange( size_t nRow ) const;

    bool                OverlapsClipRange(size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow) const;

    size_t       GetMirrorCol( size_t nCol ) const { return mnWidth - nCol - 1; }

    tools::Long                GetColPosition( size_t nCol ) const;
@@ -328,6 +330,23 @@ bool ArrayImpl::IsRowInClipRange( size_t nRow ) const
    return (mnFirstClipRow <= nRow) && (nRow <= mnLastClipRow);
}

bool ArrayImpl::OverlapsClipRange(size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow) const
{
    if(nLastCol < mnFirstClipCol)
        return false;

    if(nFirstCol > mnLastClipCol)
        return false;

    if(nLastRow < mnFirstClipRow)
        return false;

    if(nFirstRow > mnLastClipRow)
        return false;

    return true;
}

bool ArrayImpl::IsInClipRange( size_t nCol, size_t nRow ) const
{
    return IsColInClipRange( nCol ) && IsRowInClipRange( nRow );
@@ -1020,6 +1039,84 @@ static void HelperCreateVerticalEntry(
    rInstance.addSdrConnectStyleData(false, rEndFromTL, -rY - rX, true);
}

static void HelperCreateTLBREntry(
    const Array& rArray,
    const Style& rStyle,
    drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
    const basegfx::B2DPoint& rOrigin,
    const basegfx::B2DVector& rX,
    const basegfx::B2DVector& rY,
    size_t nColLeft,
    size_t nColRight,
    size_t nRowTop,
    size_t nRowBottom,
    const Color* pForceColor)
{
    if(rStyle.IsUsed())
    {
        /// top-left and bottom-right Style Tables
        rData.emplace_back(
            rOrigin,
            rX + rY,
            rStyle,
            pForceColor);
        drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());

        /// Fill top-left Style Table
        const Style& rTLFromRight(rArray.GetCellStyleTop(nColLeft, nRowTop));
        const Style& rTLFromBottom(rArray.GetCellStyleLeft(nColLeft, nRowTop));

        rInstance.addSdrConnectStyleData(true, rTLFromRight, rX, false);
        rInstance.addSdrConnectStyleData(true, rTLFromBottom, rY, false);

        /// Fill bottom-right Style Table
        const Style& rBRFromBottom(rArray.GetCellStyleRight(nColRight, nRowBottom));
        const Style& rBRFromLeft(rArray.GetCellStyleBottom(nColRight, nRowBottom));

        rInstance.addSdrConnectStyleData(false, rBRFromBottom, -rY, true);
        rInstance.addSdrConnectStyleData(false, rBRFromLeft, -rX, true);
    }
}

static void HelperCreateBLTREntry(
    const Array& rArray,
    const Style& rStyle,
    drawinglayer::primitive2d::SdrFrameBorderDataVector& rData,
    const basegfx::B2DPoint& rOrigin,
    const basegfx::B2DVector& rX,
    const basegfx::B2DVector& rY,
    size_t nColLeft,
    size_t nColRight,
    size_t nRowTop,
    size_t nRowBottom,
    const Color* pForceColor)
{
    if(rStyle.IsUsed())
    {
        /// bottom-left and top-right Style Tables
        rData.emplace_back(
            rOrigin + rY,
            rX - rY,
            rStyle,
            pForceColor);
        drawinglayer::primitive2d::SdrFrameBorderData& rInstance(rData.back());

        /// Fill bottom-left Style Table
        const Style& rBLFromTop(rArray.GetCellStyleLeft(nColLeft, nRowBottom));
        const Style& rBLFromBottom(rArray.GetCellStyleBottom(nColLeft, nRowBottom));

        rInstance.addSdrConnectStyleData(true, rBLFromTop, -rY, true);
        rInstance.addSdrConnectStyleData(true, rBLFromBottom, rX, false);

        /// Fill top-right Style Table
        const Style& rTRFromLeft(rArray.GetCellStyleTop(nColRight, nRowTop));
        const Style& rTRFromBottom(rArray.GetCellStyleRight(nColRight, nRowTop));

        rInstance.addSdrConnectStyleData(false, rTRFromLeft, -rX, true);
        rInstance.addSdrConnectStyleData(false, rTRFromBottom, rY, false);
    }
}

drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
    size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow,
    const Color* pForceColor ) const
@@ -1143,88 +1240,60 @@ drawinglayer::primitive2d::Primitive2DContainer Array::CreateB2DPrimitiveRange(
                    }
                }

                // check for crossed lines, these need special treatment, especially
                // for merged cells, see below
                const Style& rTLBR(GetCellStyleTLBR(nCol, nRow));
                const Style& rBLTR(GetCellStyleBLTR(nCol, nRow));

                if(rTLBR.IsUsed() || rBLTR.IsUsed())
                // tdf#126269 check for crossed lines, these need special treatment, especially
                // for merged cells (see comments in task). Separate treatment of merged and
                // non-merged cells to allow better handling of both types
                if(rCell.IsMerged())
                {
                    bool bContinue(true);
                    // first check if this merged cell was already handled. To do so,
                    // calculate and use the index of the TopLeft cell
                    size_t nColLeft(nCol);
                    size_t nRowTop(nRow);
                    size_t nColRight(nCol);
                    size_t nRowBottom(nRow);
                    GetMergedRange(nColLeft, nRowTop, nColRight, nRowBottom, nCol, nRow);
                    const size_t nIndexOfMergedCell(mxImpl->GetIndex(nColLeft, nRowTop));

                    if(rCell.IsMerged())
                    if(aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell))
                    {
                        // first check if this merged cell was already handled. To do so,
                        // calculate and use the index of the TopLeft cell
                        const size_t _nMergedFirstCol(mxImpl->GetMergedFirstCol(nCol, nRow));
                        const size_t _nMergedFirstRow(mxImpl->GetMergedFirstRow(nCol, nRow));
                        const size_t nIndexOfMergedCell(mxImpl->GetIndex(_nMergedFirstCol, _nMergedFirstRow));
                        bContinue = (aMergedCells.end() == aMergedCells.find(nIndexOfMergedCell));
                        // not found, so not yet handled. Add now to mark as handled
                        aMergedCells.insert(nIndexOfMergedCell);

                        if(bContinue)
                        // get and check if diagonal styles are used
                        const Style& rTLBR(GetCellStyleTLBR(nColLeft, nRowTop));
                        const Style& rBLTR(GetCellStyleBLTR(nColLeft, nRowTop));

                        if(rTLBR.IsUsed() || rBLTR.IsUsed())
                        {
                            // not found, add now to mark as handled
                            aMergedCells.insert(nIndexOfMergedCell);
                            // test for in ClipRange for BottomRight corner of merged cell
                            if(mxImpl->OverlapsClipRange(nColLeft, nRowTop, nColRight, nRowBottom))
                            {
                                // when merged, get extended coordinate system and derived values
                                // for the full range of this merged cell
                                aCoordinateSystem = rCell.CreateCoordinateSystem(*this, nCol, nRow, true);
                                aX = basegfx::utils::getColumn(aCoordinateSystem, 0);
                                aY = basegfx::utils::getColumn(aCoordinateSystem, 1);
                                aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2);

                            // when merged, get extended coordinate system and derived values
                            // for the full range of this merged cell
                            aCoordinateSystem = rCell.CreateCoordinateSystem(*this, nCol, nRow, true);
                            aX = basegfx::utils::getColumn(aCoordinateSystem, 0);
                            aY = basegfx::utils::getColumn(aCoordinateSystem, 1);
                            aOrigin = basegfx::utils::getColumn(aCoordinateSystem, 2);
                                HelperCreateTLBREntry(*this, rTLBR, *aData, aOrigin, aX, aY, nColLeft, nRowTop, nColRight, nRowBottom, pForceColor);
                                HelperCreateBLTREntry(*this, rBLTR, *aData, aOrigin, aX, aY, nColLeft, nRowTop, nColRight, nRowBottom, pForceColor);
                            }
                        }
                    }

                    if(bContinue)
                }
                else
                {
                    // must be in clipping range: else not visible
                    if( mxImpl->IsInClipRange( nCol, nRow ) )
                    {
                        if(rTLBR.IsUsed())
                        // get and check if diagonal styles are used
                        const Style& rTLBR(GetCellStyleTLBR(nCol, nRow));
                        const Style& rBLTR(GetCellStyleBLTR(nCol, nRow));

                        if(rTLBR.IsUsed() || rBLTR.IsUsed())
                        {
                            /// top-left and bottom-right Style Tables
                            aData->emplace_back(
                                aOrigin,
                                aX + aY,
                                rTLBR,
                                pForceColor);
                            drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());

                            /// Fill top-left Style Table
                            const Style& rTLFromRight(GetCellStyleTop(nCol, nRow));
                            const Style& rTLFromBottom(GetCellStyleLeft(nCol, nRow));

                            rInstance.addSdrConnectStyleData(true, rTLFromRight, aX, false);
                            rInstance.addSdrConnectStyleData(true, rTLFromBottom, aY, false);

                            /// Fill bottom-right Style Table
                            const Style& rBRFromBottom(GetCellStyleRight(nCol, nRow));
                            const Style& rBRFromLeft(GetCellStyleBottom(nCol, nRow));

                            rInstance.addSdrConnectStyleData(false, rBRFromBottom, -aY, true);
                            rInstance.addSdrConnectStyleData(false, rBRFromLeft, -aX, true);
                        }

                        if(rBLTR.IsUsed())
                        {
                            /// bottom-left and top-right Style Tables
                            aData->emplace_back(
                                aOrigin + aY,
                                aX - aY,
                                rBLTR,
                                pForceColor);
                            drawinglayer::primitive2d::SdrFrameBorderData& rInstance(aData->back());

                            /// Fill bottom-left Style Table
                            const Style& rBLFromTop(GetCellStyleLeft(nCol, nRow));
                            const Style& rBLFromBottom(GetCellStyleBottom(nCol, nRow));

                            rInstance.addSdrConnectStyleData(true, rBLFromTop, -aY, true);
                            rInstance.addSdrConnectStyleData(true, rBLFromBottom, aX, false);

                            /// Fill top-right Style Table
                            const Style& rTRFromLeft(GetCellStyleTop(nCol, nRow));
                            const Style& rTRFromBottom(GetCellStyleRight(nCol, nRow));

                            rInstance.addSdrConnectStyleData(false, rTRFromLeft, -aX, true);
                            rInstance.addSdrConnectStyleData(false, rTRFromBottom, aY, false);
                            HelperCreateTLBREntry(*this, rTLBR, *aData, aOrigin, aX, aY, nCol, nRow, nCol, nRow, pForceColor);
                            HelperCreateBLTREntry(*this, rBLTR, *aData, aOrigin, aX, aY, nCol, nRow, nCol, nRow, pForceColor);
                        }
                    }
                }