borderline: adaptions to primitives

Handling and paint of borderlines greatly adapted
to primitive usage. Solved the double paint mechanisn
to no longer use the sc-local special cases. The
svx tooling for borderline paint is now the only one
and was extended to also handle diagonal lines.
Big cleanups/removals of old paint to OutputDevice
and sc-specific rendering. All other app-usages
of borderline also adapted. Preparations for careful
line-start/end adaption prepared and possible due to
unified coordinate-system usages and basegfx class-usage

Change-Id: If9e4efcfc0fe25e14d4052907038ca5cf222a432
diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx
index b907958..b0c11e2 100644
--- a/include/svx/framelink.hxx
+++ b/include/svx/framelink.hxx
@@ -32,6 +32,7 @@
class Point;
namespace tools { class Rectangle; }
class OutputDevice;
namespace svx { namespace frame { class Cell; }}

namespace svx {
namespace frame {
@@ -157,6 +158,9 @@ public:
    /** Returns this style mirrored, if it is a double frame style, otherwise a simple copy. */
    Style               Mirror() const;

    /** return the Cell using this style (if set) */
    const Cell* GetUsingCell() const { return mpUsingCell; }

private:
    Color               maColorPrim;
    Color               maColorSecn;
@@ -168,6 +172,13 @@ private:
    double              mfSecn;     /// Width of secondary (right or bottom) line.
    double              mfPatternScale; /// Scale used for line pattern spacing.
    SvxBorderLineStyle  mnType;

    /// need information which cell this style info comes from due to needed
    /// rotation info (which is in the cell). Rotation depends on the cell.
    /// Encapsulated using a single static friend method that is the single
    /// allowed instance to set/modify this value
    friend void exclusiveSetUsigCellAtStyle(Style& rStyle, const Cell* pCell);
    const Cell*         mpUsingCell;
};

bool operator==( const Style& rL, const Style& rR );
@@ -277,78 +288,6 @@ inline double GetVerDiagAngle( const tools::Rectangle& rRect )
 */
SVX_DLLPUBLIC long GetTLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle );

/** Returns an X coordinate for a diagonal frame border in the specified height.

    This function is for usage with the bottom-left end of a bottom-left to
    top-right diagonal frame border, connected to the left end of a horizontal
    frame border.

    The function returns the relative X position (i.e. for a polygon) of the
    diagonal frame border according to the specified relative Y position. The
    mentioned positions are relative to the reference point of both frame
    borders.

             Primary -->/     /<--- Secondary
                       /     /
                      /     /       The function calculates the X position of i.e.
    - - - - - - - - -/- - -X <----- this point (relative from X of reference point).
      ^         +---/     /------------------------------------------------
     nVerOffs   |  /     / <--- The diagonal frame border.
      v         | /  |  /
    - - - - - - |  --+--  <---- Reference point for horizontal and diagonal frame borders.
                |    |
                |               The horizontal frame border.
                +----------------------------------------------------------

    @param nVerOffs
        The vertical position of the point to be calculated, relative to the Y
        coordinate of the reference point.
    @param nDiagOffs
        The width offset across the diagonal frame border (0 = middle),
        regardless of the gradient of the diagonal frame border (always
        vertical to the direction of the diagonal frame border). This value is
        not related in any way to the reference point. For details about
        relative width offsets, see description of class Style.
    @param fAngle
        Inner (right) angle between diagonal and horizontal frame border.
 */
long GetBLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle );

/** Returns an X coordinate for a diagonal frame border in the specified height.

    This function is for usage with the bottom-right end of a top-left to
    bottom-right diagonal frame border, connected to the right end of a
    horizontal frame border.

    @param nDiagOffs
        The width offset across the diagonal frame border (0 = middle),
        regardless of the gradient of the diagonal frame border (always
        vertical to the direction of the diagonal frame border). This value is
        not related in any way to the reference point. For details about
        relative width offsets, see description of class Style.
    @param fAngle
        Inner (left) angle between diagonal and horizontal frame border.
 */
long GetBRDiagOffset( long nDiagOffs, double fAngle );

/** Returns an X coordinate for a diagonal frame border in the specified height.

    This function is for usage with the top-right end of a bottom-left to
    top-right diagonal frame border, connected to the right end of a horizontal
    frame border.

    @param nDiagOffs
        The width offset across the diagonal frame border (0 = middle),
        regardless of the gradient of the diagonal frame border (always
        vertical to the direction of the diagonal frame border). This value is
        not related in any way to the reference point. For details about
        relative width offsets, see description of class Style.
    @param fAngle
        Inner (left) angle between diagonal and horizontal frame border.
 */
long GetTRDiagOffset( long nDiagOffs, double fAngle );


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

    Two borders are "connectable" in terms of this function, if both can be
@@ -431,8 +370,11 @@ SVX_DLLPUBLIC bool CheckFrameBorderConnectable(
 */
SVX_DLLPUBLIC void CreateBorderPrimitives(
    drawinglayer::primitive2d::Primitive2DContainer&    rTarget,        /// target for created primitives
    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 basegfx::B2DPoint&    rOrigin,    /// start point of borderline
    const basegfx::B2DVector&   rX,         /// X-Axis with length
    const basegfx::B2DVector&   rY,         /// Y-Axis for perpendicular, normalized. Does *not* need to be perpendicular, but may express a rotation

    const Style&        rBorder,        /// Style of the processed frame border.

    const DiagStyle&    rLFromTR,       /// Diagonal frame border from top-right to left end of rBorder.
@@ -447,15 +389,16 @@ SVX_DLLPUBLIC void CreateBorderPrimitives(
    const Style&        rRFromB,        /// Vertical frame border from bottom to right end of rBorder.
    const DiagStyle&    rRFromBL,       /// Diagonal frame border from bottom-left to right end of rBorder.

    const Color*        pForceColor,    /// If specified, overrides frame border color.
    const long          rRotationT = 9000, /// Angle of the top slanted frames in 100th of degree
    const long          rRotationB = 9000  /// Angle of the bottom slanted frames in 100th of degree
    const Color*        pForceColor     /// If specified, overrides frame border color.
);

SVX_DLLPUBLIC void CreateBorderPrimitives(
    drawinglayer::primitive2d::Primitive2DContainer&    rTarget,        /// target for created primitives
    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 basegfx::B2DPoint&    rOrigin,    /// start point of borderline
    const basegfx::B2DVector&   rX,         /// X-Axis with length
    const basegfx::B2DVector&   rY,         /// Y-Axis for perpendicular, normalized. Does *not* need to be perpendicular, but may express a rotation

    const Style&        rBorder,        /// Style of the processed frame border.

    const Style&        rLFromT,        /// Vertical frame border from top to left end of rBorder.
@@ -466,9 +409,7 @@ SVX_DLLPUBLIC void CreateBorderPrimitives(
    const Style&        rRFromR,        /// Horizontal frame border from right to right end of rBorder.
    const Style&        rRFromB,        /// Vertical frame border from bottom to right end of rBorder.

    const Color*        pForceColor,    /// If specified, overrides frame border color.
    const long          rRotationT = 9000, /// Angle of the top slanted frame in 100th of degrees
    const long          rRotationB = 9000  /// Angle of the bottom slanted frame in 100th of degrees
    const Color*        pForceColor     /// If specified, overrides frame border color.
);

/** Draws both diagonal frame borders, regards all connected frame styles.
@@ -479,7 +420,10 @@ The function preserves all settings of the passed output device.
*/
SVX_DLLPUBLIC void CreateDiagFrameBorderPrimitives(
    drawinglayer::primitive2d::Primitive2DContainer&    rTarget,        /// target for created primitives
    const basegfx::B2DRange&                            rRange,         /// geometrical definition for both diagonal frame borders.

    const basegfx::B2DPoint&                            rOrigin,        /// Origin of the coordinate system spawning the cell
    const basegfx::B2DVector&                           rXAxis,         /// X-Axis of the coordinate system spawning the cell
    const basegfx::B2DVector&                           rYAxis,         /// Y-Axis of the coordinate system spawning the cell

    const Style&        rTLBR,          /// Style of the processed top-left to bottom-right diagonal frame border.
    const Style&        rBLTR,          /// Style of the processed bottom-left to top-right diagonal frame border.
@@ -494,164 +438,7 @@ SVX_DLLPUBLIC void CreateDiagFrameBorderPrimitives(
    const Style&        rTRFromB,       /// Vertical frame border from bottom to top-right end of rBLTR.
    const Style&        rTRFromL,       /// Horizontal frame border from left to top-right end of rBLTR.

    const Color*        pForceColor,        /// If specified, overrides frame border color.
    const long          nRotationT = 9000,  /// Angle of the top slanted frame in 100th of degrees
    const long          nRotationB = 9000   /// Angle of the bottom slanted frame in 100th of degrees
);

/** Draws a horizontal frame border, regards all connected frame styles.

    The frame style to draw is passed as parameter rBorder. The function
    calculates the adjustment in X direction for left and right end of primary
    and secondary line of the frame border (the style may present a double
    line). The line ends may differ according to the connected frame styles
    coming from top, bottom, left, right, and/or diagonal.

    Thick frame styles are always drawn centered (in width) to the passed
    reference points. The Y coordinates of both reference points must be equal
    (the line cannot be drawn slanted).

    The function preserves all settings of the passed output device.

    All parameters starting with "rL" refer to the left end of the processed
    frame border, all parameters starting with "rR" refer to the right end.
    The following part of the parameter name starting with "From" specifies
    where the frame border comes from. Example: "rLFromTR" means the frame
    border coming from top-right, connected to the left end of rBorder (and
    therefore a diagonal frame border).

    The follong picture shows the meaning of all passed parameters:

                 rLFromT      /                   \      rRFromT
                    |       /                       \       |
                    |   rLFromTR               rRFromTL     |
                    |   /                               \   |
                    | /                                   \ |
    --- rLFromL ---   ============== rBorder ==============   --- rRFromR ---
                    | \                                   / |
                    |   \                               /   |
                    |   rLFromBR               rRFromBL     |
                    |       \                       /       |
                 rLFromB      \                   /      rRFromB
 */
SVX_DLLPUBLIC void DrawHorFrameBorder(
    OutputDevice&       rDev,           /// The output device used to draw the frame border.

    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.

    const DiagStyle&    rLFromTR,       /// Diagonal frame border from top-right to left end of rBorder.
    const Style&        rLFromT,        /// Vertical frame border from top to left end of rBorder.
    const Style&        rLFromL,        /// Horizontal frame border from left to left end of rBorder.
    const Style&        rLFromB,        /// Vertical frame border from bottom to left end of rBorder.
    const DiagStyle&    rLFromBR,       /// Diagonal frame border from bottom-right to left end of rBorder.

    const DiagStyle&    rRFromTL,       /// Diagonal frame border from top-left to right end of rBorder.
    const Style&        rRFromT,        /// Vertical frame border from top to right end of rBorder.
    const Style&        rRFromR,        /// Horizontal frame border from right to right end of rBorder.
    const Style&        rRFromB,        /// Vertical frame border from bottom to right end of rBorder.
    const DiagStyle&    rRFromBL,       /// Diagonal frame border from bottom-left to right end of rBorder.

    const Color*        pForceColor = nullptr /// If specified, overrides frame border color.
);


/** Draws a vertical frame border, regards all connected frame styles.

    The frame style to draw is passed as parameter rBorder. The function
    calculates the adjustment in Y direction for top and bottom end of primary
    and secondary line of the frame border (the style may present a double
    line). The line ends may differ according to the connected frame styles
    coming from left, right, top, bottom, and/or diagonal.

    Thick frame styles are always drawn centered (in width) to the passed
    reference points. The X coordinates of both reference points must be equal
    (the line cannot be drawn slanted).

    The function preserves all settings of the passed output device.

    All parameters starting with "rT" refer to the top end of the processed
    frame border, all parameters starting with "rB" refer to the bottom end.
    The following part of the parameter name starting with "From" specifies
    where the frame border comes from. Example: "rTFromBL" means the frame
    border coming from bottom-left, connected to the top end of rBorder (and
    therefore a diagonal frame border).

    The follong picture shows the meaning of all passed parameters:

                    |
                 rTFromT
                    |
                    |
    --- rTFromL ---   --- rTFromR ---
                  / # \
                /   #   \
        rTFromBL    #   rTFromBR
            /       #       \
          /         #         \
                    #
                 rBorder
                    #
          \         #         /
            \       #       /
        rBFromTL    #   rBFromTR
                \   #   /
                  \ # /
    --- rBFromL ---   --- rBFromR ---
                    |
                    |
                 rBFromB
                    |
 */
SVX_DLLPUBLIC void DrawVerFrameBorder(
    OutputDevice&       rDev,           /// The output device used to draw the frame border.

    const Point&        rTPos,          /// Reference point for top end of the processed frame border.
    const Point&        rBPos,          /// Reference point for bottom end of the processed frame border.
    const Style&        rBorder,        /// Style of the processed frame border.

    const DiagStyle&    rTFromBL,       /// Diagonal frame border from bottom-right to top end of rBorder.
    const Style&        rTFromL,        /// Horizontal frame border from left to top end of rBorder.
    const Style&        rTFromT,        /// Vertical frame border from top to top end of rBorder.
    const Style&        rTFromR,        /// Horizontal frame border from right to top end of rBorder.
    const DiagStyle&    rTFromBR,       /// Diagonal frame border from bottom-right to top end of rBorder.

    const DiagStyle&    rBFromTL,       /// Diagonal frame border from top-left to bottom end of rBorder.
    const Style&        rBFromL,        /// Horizontal frame border from left to bottom end of rBorder.
    const Style&        rBFromB,        /// Vertical frame border from bottom to bottom end of rBorder.
    const Style&        rBFromR,        /// Horizontal frame border from right to bottom end of rBorder.
    const DiagStyle&    rBFromTR,       /// Diagonal frame border from top-right to bottom end of rBorder.

    const Color*        pForceColor = nullptr /// If specified, overrides frame border color.
);


/** Draws both diagonal frame borders, regards all connected frame styles.

    One or both passed diagonal frame styles may be invisible.

    The function preserves all settings of the passed output device.
 */
SVX_DLLPUBLIC void DrawDiagFrameBorders(
    OutputDevice&       rDev,           /// The output device used to draw the frame border.

    const tools::Rectangle&    rRect,          /// Rectangle for both diagonal frame borders.
    const Style&        rTLBR,          /// Style of the processed top-left to bottom-right diagonal frame border.
    const Style&        rBLTR,          /// Style of the processed bottom-left to top-right diagonal frame border.

    const Style&        rTLFromB,       /// Vertical frame border from bottom to top-left end of rTLBR.
    const Style&        rTLFromR,       /// Horizontal frame border from right to top-left end of rTLBR.
    const Style&        rBRFromT,       /// Vertical frame border from top to bottom-right end of rTLBR.
    const Style&        rBRFromL,       /// Horizontal frame border from left to bottom-right end of rTLBR.

    const Style&        rBLFromT,       /// Vertical frame border from top to bottom-left end of rBLTR.
    const Style&        rBLFromR,       /// Horizontal frame border from right to bottom-left end of rBLTR.
    const Style&        rTRFromB,       /// Vertical frame border from bottom to top-right end of rBLTR.
    const Style&        rTRFromL,       /// Horizontal frame border from left to top-right end of rBLTR.

    const Color*        pForceColor,    /// If specified, overrides frame border color.
    bool                bDiagDblClip    /// true = Use clipping for crossing double frame borders.
    const Color*        pForceColor     /// If specified, overrides frame border color.
);


diff --git a/include/svx/framelinkarray.hxx b/include/svx/framelinkarray.hxx
index 9208f67..15d8dcf 100644
--- a/include/svx/framelinkarray.hxx
+++ b/include/svx/framelinkarray.hxx
@@ -23,6 +23,7 @@
#include <drawinglayer/processor2d/baseprocessor2d.hxx>
#include <svx/framelink.hxx>
#include <svx/svxdllapi.h>
#include <svx/rotmodit.hxx>
#include <memory>
#include <vector>

@@ -119,6 +120,12 @@ public:
    /** Sets the bottom frame style of the specified row. Ignores merged ranges. */
    void                SetRowStyleBottom( size_t nRow, const Style& rStyle );

    /** Sets the rotation parameters of the cell (nCol,nRow). Ignores merged ranges. */
    void                SetCellRotation(size_t nCol, size_t nRow, SvxRotateMode eRotMode, double fOrientation);

    /** Check if at least one cell is rotated */
    bool                HasCellRotation() const;

    /** Returns the left frame style of the cell (nCol,nRow).
        Returns thicker of own left style or right style of the cell to the left.
        Returns the style only if visible (i.e. at left border of a merged range).
@@ -246,9 +253,6 @@ public:
            clipped too. This array can handle only one clip range at a time. */
    void                SetClipRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow );

    /** Returns the rectangle (output coordinates) of the current clipping range. */
    tools::Rectangle           GetClipRangeRectangle() const;

    // cell coordinates -------------------------------------------------------

    /** Sets the X output coordinate of the left column. */
@@ -313,14 +317,6 @@ public:
        Returns the vertical angle of merged ranges. */
    double              GetVerDiagAngle( size_t nCol, size_t nRow ) const;

    /** Specifies whether to use polygon clipping to draw diagonal frame borders.
        @descr
            If enabled, diagonal frame borders are drawn interrupted, if they are
            crossed by a double frame border. Polygon clipping is very expensive
            and should only be used for very small output devices (i.e. in the
            Border tab page). Default after construction is OFF. */
    void                SetUseDiagDoubleClipping( bool bSet );

    // mirroring --------------------------------------------------------------

    /** Mirrors the entire array horizontally. */
@@ -336,16 +332,6 @@ public:
                            size_t nLastCol, size_t nLastRow,
                            const Color* pForceColor ) const;

    /** 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( OutputDevice& rDev,
                            size_t nFirstCol, size_t nFirstRow,
                            size_t nLastCol, size_t nLastRow ) const;

    /** Draws the part of the array, that is inside the clipping range. */
    void                DrawArray(OutputDevice& rDev) const;

    /** Draws the part of the array, that is inside the clipping range. */
    void                DrawArray(drawinglayer::processor2d::BaseProcessor2D& rProcessor) const;

diff --git a/sc/source/core/data/fillinfo.cxx b/sc/source/core/data/fillinfo.cxx
index e5aadd5..a7d9912 100644
--- a/sc/source/core/data/fillinfo.cxx
+++ b/sc/source/core/data/fillinfo.cxx
@@ -936,7 +936,6 @@ void ScDocument::FillInfo(

    svx::frame::Array& rArray = rTabInfo.maArray;
    rArray.Initialize( nColCount, nRowCount );
    rArray.SetUseDiagDoubleClipping( false );

    for( size_t nRow = 0; nRow < nRowCount; ++nRow )
    {
diff --git a/sc/source/ui/inc/output.hxx b/sc/source/ui/inc/output.hxx
index 8aeee70..5345b69 100644
--- a/sc/source/ui/inc/output.hxx
+++ b/sc/source/ui/inc/output.hxx
@@ -196,7 +196,6 @@ private:

    bool    bSnapPixel;

    bool    bAnyRotated;        // internal
    bool    bAnyClipped;        // internal
    bool    bTabProtected;
    bool    bLayoutRTL;
@@ -302,7 +301,7 @@ public:
                    // with logic MapMode set!
    void    DrawEdit(bool bPixelToLogic);

    void    FindRotated();
    void    SetCellRotations();
    void    DrawRotated(bool bPixelToLogic);        // logical

    void    DrawClear();
diff --git a/sc/source/ui/miscdlgs/autofmt.cxx b/sc/source/ui/miscdlgs/autofmt.cxx
index 0a7f9de..8fd5909 100644
--- a/sc/source/ui/miscdlgs/autofmt.cxx
+++ b/sc/source/ui/miscdlgs/autofmt.cxx
@@ -36,6 +36,7 @@
#include <vcl/builderfactory.hxx>
#include <sfx2/viewfrm.hxx>
#include <comphelper/processfactory.hxx>
#include <drawinglayer/processor2d/processor2dtools.hxx>

#include "strings.hrc"
#include "scmod.hxx"
@@ -393,7 +394,19 @@ void ScAutoFmtPreview::PaintCells(vcl::RenderContext& rRenderContext)

        // 3) border
        if (pCurData->GetIncludeFrame())
            maArray.DrawArray(rRenderContext);
        {
            const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
            std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
                drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
                    rRenderContext,
                    aNewViewInformation2D));

            if (pProcessor2D)
            {
                maArray.DrawArray(*pProcessor2D.get());
                pProcessor2D.reset();
            }
        }
    }
}

@@ -401,7 +414,7 @@ void ScAutoFmtPreview::Init()
{
    SetBorderStyle( WindowBorderStyle::MONO );
    maArray.Initialize( 5, 5 );
    maArray.SetUseDiagDoubleClipping( false );
//    maArray.SetUseDiagDoubleClipping( false );
    mnLabelColWidth = 0;
    mnDataColWidth1 = 0;
    mnDataColWidth2 = 0;
diff --git a/sc/source/ui/view/gridwin4.cxx b/sc/source/ui/view/gridwin4.cxx
index 68a1ec5..a0ea195 100644
--- a/sc/source/ui/view/gridwin4.cxx
+++ b/sc/source/ui/view/gridwin4.cxx
@@ -699,6 +699,10 @@ void ScGridWindow::DrawContent(OutputDevice &rDevice, const ScTableInfo& rTableI
        pContentDev->SetMapMode(aCurrentMapMode);
    }

    // check for and set cell rotations at OutputData to have it available
    // in the svx tooling to render the borders
    aOutputData.SetCellRotations();

    if ( rDoc.HasBackgroundDraw( nTab, aDrawingRectLogic ) )
    {
        pContentDev->SetMapMode(MapUnit::MapPixel);
diff --git a/sc/source/ui/view/output.cxx b/sc/source/ui/view/output.cxx
index b6d7363..f4db5fe 100644
--- a/sc/source/ui/view/output.cxx
+++ b/sc/source/ui/view/output.cxx
@@ -183,7 +183,6 @@ ScOutputData::ScOutputData( OutputDevice* pNewDev, ScOutputType eNewType,
    bShowSpellErrors( false ),
    bMarkClipped( false ), // sal_False for printer/metafile etc.
    bSnapPixel( false ),
    bAnyRotated( false ),
    bAnyClipped( false ),
    mpTargetPaintWindow(nullptr), // #i74769# use SdrPaintWindow direct
    mpSpellCheckCxt(nullptr)
@@ -618,7 +617,7 @@ void ScOutputData::SetPagebreakMode( ScPageBreakData* pPageData )
    }
}

void ScOutputData::FindRotated()
void ScOutputData::SetCellRotations()
{
    //! save nRotMax
    SCCOL nRotMax = nX2;
@@ -652,8 +651,16 @@ void ScOutputData::FindRotated()
                    ScRotateDir nDir = pPattern->GetRotateDir( pCondSet );
                    if (nDir != ScRotateDir::NONE)
                    {
                        // Needed for CellInfo internal decisions (bg fill, ...)
                        pInfo->nRotateDir = nDir;
                        bAnyRotated = true;

                        // add rotation info to Array information
                        const long nAttrRotate(pPattern->GetRotateVal(pCondSet));
                        const SvxRotateMode eRotMode((SvxRotateMode)static_cast<const SvxRotateModeItem&>(pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue());
                        const double fOrient((bLayoutRTL ? -1.0 : 1.0) * nAttrRotate * F_PI18000); // 1/100th degrees -> [0..2PI]
                        svx::frame::Array& rArray = mrTabInfo.maArray;

                        rArray.SetCellRotation(nY+1, nX+1, eRotMode, fOrient);
                    }
                }
            }
@@ -985,8 +992,6 @@ void drawCells(vcl::RenderContext& rRenderContext, const Color* pColor, const Sv

void ScOutputData::DrawBackground(vcl::RenderContext& rRenderContext)
{
    FindRotated();              //! from the outside?

    Size aOnePixel = rRenderContext.PixelToLogic(Size(1,1));
    long nOneXLogic = aOnePixel.Width();
    long nOneYLogic = aOnePixel.Height();
@@ -1380,8 +1385,10 @@ void ScOutputData::DrawFrame(vcl::RenderContext& rRenderContext)

    const Color* pForceColor = bUseSingleColor ? &aSingleColor : nullptr;

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

    long nInitPosX = nScrX;
    if ( bLayoutRTL )
@@ -1617,16 +1624,16 @@ void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Co
                    SvxRotateMode eRotMode = (SvxRotateMode)static_cast<const SvxRotateModeItem&>(
                                    pPattern->GetItem(ATTR_ROTATE_MODE, pCondSet)).GetValue();

                    if ( nAttrRotate )
                    if (nAttrRotate)
                    {
                        if (nX<nX1)         // compute negative position
                        if (nX < nX1)         // compute negative position
                        {
                            nPosX = nInitPosX;
                            SCCOL nCol = nX1;
                            while (nCol > nX)
                            {
                                --nCol;
                                nPosX -= nLayoutSign * (long) pRowInfo[0].pCellInfo[nCol+1].nWidth;
                                nPosX -= nLayoutSign * (long)pRowInfo[0].pCellInfo[nCol + 1].nWidth;
                            }
                        }

@@ -1636,248 +1643,100 @@ void ScOutputData::DrawRotatedFrame(vcl::RenderContext& rRenderContext, const Co
                        long nTop = nPosY - 1;
                        long nBottom = nPosY + nRowHeight - 1;
                        long nTopLeft = nPosX - nLayoutSign;
                        long nTopRight = nPosX + ( nColWidth - 1 ) * nLayoutSign;
                        long nTopRight = nPosX + (nColWidth - 1) * nLayoutSign;
                        long nBotLeft = nTopLeft;
                        long nBotRight = nTopRight;

                        // inclusion of the sign here hasn't been decided yet
                        // (if not, the extension of the non-rotated background must also be changed)
                        double nRealOrient = nLayoutSign * nAttrRotate * F_PI18000;     // 1/100th degrees
                        double nCos = cos( nRealOrient );
                        double nSin = sin( nRealOrient );
                        double nCos = cos(nRealOrient);
                        double nSin = sin(nRealOrient);
                        //! restrict !!!
                        long nSkew = (long) ( nRowHeight * nCos / nSin );
                        long nSkew = (long)(nRowHeight * nCos / nSin);

                        switch (eRotMode)
                        {
                            case SVX_ROTATE_MODE_BOTTOM:
                                nTopLeft += nSkew;
                                nTopRight += nSkew;
                                break;
                            case SVX_ROTATE_MODE_CENTER:
                                nSkew /= 2;
                                nTopLeft += nSkew;
                                nTopRight += nSkew;
                                nBotLeft -= nSkew;
                                nBotRight -= nSkew;
                                break;
                            case SVX_ROTATE_MODE_TOP:
                                nBotLeft -= nSkew;
                                nBotRight -= nSkew;
                                break;
                            default:
                            {
                                // added to avoid warnings
                            }
                        case SVX_ROTATE_MODE_BOTTOM:
                            nTopLeft += nSkew;
                            nTopRight += nSkew;
                            break;
                        case SVX_ROTATE_MODE_CENTER:
                            nSkew /= 2;
                            nTopLeft += nSkew;
                            nTopRight += nSkew;
                            nBotLeft -= nSkew;
                            nBotRight -= nSkew;
                            break;
                        case SVX_ROTATE_MODE_TOP:
                            nBotLeft -= nSkew;
                            nBotRight -= nSkew;
                            break;
                        default:
                        {
                            // added to avoid warnings
                        }
                        }

                        Point aPoints[4];
                        aPoints[0] = Point( nTopLeft, nTop );
                        aPoints[1] = Point( nTopRight, nTop );
                        aPoints[2] = Point( nBotRight, nBottom );
                        aPoints[3] = Point( nBotLeft, nBottom );
                        aPoints[0] = Point(nTopLeft, nTop);
                        aPoints[1] = Point(nTopRight, nTop);
                        aPoints[2] = Point(nBotRight, nBottom);
                        aPoints[3] = Point(nBotLeft, nBottom);

                        const SvxBrushItem* pBackground = pInfo->pBackground;
                        if (!pBackground)
                            pBackground = static_cast<const SvxBrushItem*>( &pPattern->GetItem(
                                                ATTR_BACKGROUND, pCondSet ));
                            pBackground = static_cast<const SvxBrushItem*>(&pPattern->GetItem(
                                ATTR_BACKGROUND, pCondSet));
                        if (bCellContrast)
                        {
                            //  high contrast for cell borders and backgrounds -> empty background
                            pBackground = ScGlobal::GetEmptyBrushItem();
                        }
                        if(!pInfo->pColorScale)
                        if (!pInfo->pColorScale)
                        {
                            const Color& rColor = pBackground->GetColor();
                            if ( rColor.GetTransparency() != 255 )
                            if (rColor.GetTransparency() != 255)
                            {
                                //  draw background only for the changed row itself
                                //  (background doesn't extend into other cells).
                                //  For the borders (rotated and normal), clipping should be
                                //  set if the row isn't changed, but at least the borders
                                //  don't cover the cell contents.
                                if ( rThisRowInfo.bChanged )
                                if (rThisRowInfo.bChanged)
                                {
                                    tools::Polygon aPoly( 4, aPoints );
                                    tools::Polygon aPoly(4, aPoints);

                                    // for DrawPolygon, whitout Pen one pixel is left out
                                    // to the right and below...
                                    if ( rColor.GetTransparency() == 0 )
                                    if (rColor.GetTransparency() == 0)
                                        rRenderContext.SetLineColor(rColor);
                                    else
                                        rRenderContext.SetLineColor();
                                    rRenderContext.SetFillColor(rColor);
                                    rRenderContext.DrawPolygon( aPoly );
                                    rRenderContext.DrawPolygon(aPoly);
                                }
                            }
                        }
                        else
                        {
                            tools::Polygon aPoly( 4, aPoints );
                            tools::Polygon aPoly(4, aPoints);
                            const Color* pColor = pInfo->pColorScale.get();

                            // for DrawPolygon, whitout Pen one pixel is left out
                            // to the right and below...
                            if ( pColor->GetTransparency() == 0 )
                            if (pColor->GetTransparency() == 0)
                                rRenderContext.SetLineColor(*pColor);
                            else
                                rRenderContext.SetLineColor();
                            rRenderContext.SetFillColor(*pColor);
                            rRenderContext.DrawPolygon( aPoly );
                            rRenderContext.DrawPolygon(aPoly);

                        }

                        svx::frame::Style aTopLine, aBottomLine, aLeftLine, aRightLine;

                        if ( nX < nX1 || nX > nX2 )     // Attributes in FillInfo not set
                        {
                            //! consider page borders for printing !!!!!
                            const ::editeng::SvxBorderLine* pLeftLine;
                            const ::editeng::SvxBorderLine* pTopLine;
                            const ::editeng::SvxBorderLine* pRightLine;
                            const ::editeng::SvxBorderLine* pBottomLine;
                            mpDoc->GetBorderLines( nX, nY, nTab,
                                    &pLeftLine, &pTopLine, &pRightLine, &pBottomLine );
                            aTopLine.Set( pTopLine, mnPPTY );
                            aBottomLine.Set( pBottomLine, mnPPTY );
                            aLeftLine.Set( pLeftLine, mnPPTX );
                            aRightLine.Set( pRightLine, mnPPTX );
                        }
                        else
                        {
                            size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );
                            aTopLine = rArray.GetCellStyleTop( nCol, nRow );
                            aBottomLine = rArray.GetCellStyleBottom( nCol, nRow );
                            aLeftLine = rArray.GetCellStyleLeft( nCol, nRow );
                            aRightLine = rArray.GetCellStyleRight( nCol, nRow );
                            // in RTL mode the array is already mirrored -> swap back left/right borders
                            if( bLayoutRTL )
                                std::swap( aLeftLine, aRightLine );
                        }

                        // Horizontal lines
                        if (aTopLine.Prim() || aTopLine.Secn())
                        {
                            long nUpperRotate = lcl_getRotate( mpDoc, nTab, nX, nY - 1 );
                            drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                            svx::frame::CreateBorderPrimitives(
                                aSequence,
                                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 );
                            drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                            svx::frame::CreateBorderPrimitives(
                                aSequence,
                                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 );
                            drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                            svx::frame::CreateBorderPrimitives(
                                aSequence,
                                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 );
                            drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                            svx::frame::CreateBorderPrimitives(
                                aSequence,
                                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);
                        }
                    }
                }
                nPosX += nColWidth * nLayoutSign;
            }

            // delete the lines for normal output only afterwards in the second step

            nX = nX1 > 0 ? (nX1-1) : static_cast<SCCOL>(0);
            for (; nX<=nX2+1; nX++)         // visible part +- 1
            {
                sal_uInt16 nArrX = nX + 1;
                CellInfo& rInfo = rThisRowInfo.pCellInfo[nArrX];
                if ( rInfo.nRotateDir > ScRotateDir::Standard &&
                        !rInfo.bHOverlapped && !rInfo.bVOverlapped )
                {
                    size_t nCol = lclGetArrayColFromCellInfoX( nArrX, nX1, nX2, bLayoutRTL );

                    // horizontal: extend adjacent line
                    // (only when the rotated cell has a border)
                    ScRotateDir nDir = rInfo.nRotateDir;
                    if ( rArray.GetCellStyleTop( nCol, nRow ).Prim() )
                    {
                        svx::frame::Style aStyle( lcl_FindHorLine( mpDoc, nX, nY, nTab, nDir, true ), mnPPTY );
                        rArray.SetCellStyleTop( nCol, nRow, aStyle );
                        if( nRow > 0 )
                            rArray.SetCellStyleBottom( nCol, nRow - 1, aStyle );
                    }
                    if ( rArray.GetCellStyleBottom( nCol, nRow ).Prim() )
                    {
                        svx::frame::Style aStyle( lcl_FindHorLine( mpDoc, nX, nY, nTab, nDir, false ), mnPPTY );
                        rArray.SetCellStyleBottom( nCol, nRow, aStyle );
                        if( nRow + 1 < rArray.GetRowCount() )
                            rArray.SetCellStyleTop( nCol, nRow + 1, aStyle );
                    }

                    // always remove vertical borders
                    if( !rArray.IsMergedOverlappedLeft( nCol, nRow ) )
                    {
                        rArray.SetCellStyleLeft( nCol, nRow, svx::frame::Style() );
                        if( nCol > 0 )
                            rArray.SetCellStyleRight( nCol - 1, nRow, svx::frame::Style() );
                    }
                    if( !rArray.IsMergedOverlappedRight( nCol, nRow ) )
                    {
                        rArray.SetCellStyleRight( nCol, nRow, svx::frame::Style() );
                        if( nCol + 1 < rArray.GetColCount() )
                            rArray.SetCellStyleLeft( nCol + 1, nRow, svx::frame::Style() );
                    }

                    // remove diagonal borders
                    rArray.SetCellStyleTLBR( nCol, nRow, svx::frame::Style() );
                    rArray.SetCellStyleBLTR( nCol, nRow, svx::frame::Style() );
                }
            }
        }
        nPosY += nRowHeight;
    }
diff --git a/sc/source/ui/view/output2.cxx b/sc/source/ui/view/output2.cxx
index 7191d28..7658a37 100644
--- a/sc/source/ui/view/output2.cxx
+++ b/sc/source/ui/view/output2.cxx
@@ -4632,8 +4632,10 @@ void ScOutputData::DrawEdit(bool bPixelToLogic)

    pEngine.reset();

    if (bAnyRotated)
    if (mrTabInfo.maArray.HasCellRotation())
    {
        DrawRotated(bPixelToLogic);     //! call from outside ?
    }
}

void ScOutputData::DrawRotated(bool bPixelToLogic)
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index 3dd1b5f..c193285 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -44,146 +44,6 @@ namespace frame {

namespace {

typedef std::vector< Point > PointVec;


// Link result structs for horizontal and vertical lines and borders.

/** Result struct used by the horizontal/vertical frame link functions.

    This struct is used to return coordinate offsets for one end of a single
    line in a frame border, i.e. the left end of the primary line of a
    horizontal frame border.

    1) Usage for horizontal lines

    If this struct is returned by the lclLinkHorFrameBorder() function, each
    member refers to the X coordinate of one edge of a single line end in a
    horizontal frame border. They specify an offset to modify this coordinate
    when the line is painted. The values in this struct may change a
    rectangular line shape into a line with slanted left or right border, which
    is used to connect the line with diagonal lines.

    Usage for a left line end:          Usage for a right line end:
                mnOffs1                         mnOffs1
                <------->                       <------->
                    +-------------------------------+
                    | the original horizontal line  |
                    +-------------------------------+
                <------->                       <------->
                mnOffs2                         mnOffs2

    2) Usage for vertical lines

    If this struct is returned by the lclLinkVerFrameBorder() function, each
    member refers to the Y coordinate of one edge of a single line end in a
    vertical frame border. They specify an offset to modify this coordinate
    when the line is painted. The values in this struct may change a
    rectangular line shape into a line with slanted top or bottom border, which
    is used to connect the line with diagonal lines.

    Usage for a top line end:       mnOffs1 ^               ^ mnOffs2
                                            |   +-------+   |
                                            v   |       |   v
                                                |       |
                                                |       |
                the original vertical line ---> |       |
                                                |       |
                                                |       |
                                            ^   |       |   ^
                                            |   +-------+   |
    Usage for a bottom line end:    mnOffs1 v               v mnOffs2
 */
struct LineEndResult
{
    long                mnOffs1;    /// Offset for top or left edge, dependent of context.
    long                mnOffs2;    /// Offset for bottom or right edge, dependent of context

    explicit     LineEndResult() : mnOffs1( 0 ), mnOffs2( 0 ) {}

    void         Swap() { std::swap( mnOffs1, mnOffs2 ); }
    void         Negate() { mnOffs1 = -mnOffs1; mnOffs2 = -mnOffs2; }
};

/** Result struct used by the horizontal/vertical frame link functions.

    This struct contains the linking results for one end of a frame border,
    including both the primary and secondary line ends.
 */
struct BorderEndResult
{
    LineEndResult       maPrim;     /// Result for primary line.
    LineEndResult       maSecn;     /// Result for secondary line.
    LineEndResult       maGap;      /// Result for gap line.

    void         Negate() { maPrim.Negate(); maSecn.Negate(); maGap.Negate(); }
};

/** Result struct used by the horizontal/vertical frame link functions.

    This struct contains the linking results for both frame border ends, and
    therefore for the complete frame border.
 */
struct BorderResult
{
    BorderEndResult     maBeg;      /// Result for begin of border line (left or top end).
    BorderEndResult     maEnd;      /// Result for end of border line (right or bottom end).
};


// Link result structs for diagonal lines and borders.

/** Result struct used by the diagonal frame link functions.

    This struct contains the linking results for one line of a diagonal frame
    border.
 */
struct DiagLineResult
{
    long                mnLClip;    /// Offset for left border of clipping rectangle.
    long                mnRClip;    /// Offset for right border of clipping rectangle.
    long                mnTClip;    /// Offset for top border of clipping rectangle.
    long                mnBClip;    /// Offset for bottom border of clipping rectangle.

    explicit     DiagLineResult() : mnLClip( 0 ), mnRClip( 0 ), mnTClip( 0 ), mnBClip( 0 ) {}
};

/** Result struct used by the diagonal frame link functions.

    This struct contains the linking results for one diagonal frame border.
 */
struct DiagBorderResult
{
    DiagLineResult      maPrim;     /// Result for primary line.
    DiagLineResult      maSecn;     /// Result for secondary line.
};

/** Result struct used by the diagonal frame link functions.

    This struct contains the linking results for both diagonal frame borders.
 */
struct DiagBordersResult
{
    DiagBorderResult    maTLBR;     /// Result for top-left to bottom-right frame border.
    DiagBorderResult    maBLTR;     /// Result for bottom-left to top-right frame border.
};


/** A helper struct containing two points of a line.
 */
struct LinePoints
{
    Point               maBeg;      /// Start position of the line.
    Point               maEnd;      /// End position of the line.

    explicit            LinePoints( const Point& rBeg, const Point& rEnd ) :
                            maBeg( rBeg ), maEnd( rEnd ) {}
    explicit            LinePoints( const tools::Rectangle& rRect, bool bTLBR ) :
                            maBeg( bTLBR ? rRect.TopLeft() : rRect.TopRight() ),
                            maEnd( bTLBR ? rRect.BottomRight() : rRect.BottomLeft() ) {}
};


/** Rounds and casts a double value to a long value. */
inline long lclD2L( double fValue )
{
@@ -196,920 +56,6 @@ double lclScaleValue( double nValue, double fScale, sal_uInt16 nMaxWidth )
    return std::min<double>(nValue * fScale, nMaxWidth);
}


// Line width offset calculation.

/** Returns the start offset of the single/primary line across the frame border.

    All following lclGet*Beg() and lclGet*End() functions return sub units to
    increase the computational accuracy, where 256 sub units are equal to
    1 map unit of the used OutputDevice.

    The following pictures show the upper end of a vertical frame border and
    illustrates the return values of all following lclGet*Beg() and lclGet*End()
    functions. The first picture shows a single frame border, the second picture
    shows a double frame border.

    The functions regard the reference point handling mode of the passed border
    style.
    RefMode::Centered:
        All returned offsets are relative to the middle position of the frame
        border (offsets left of the middle are returned negative, offsets right
        of the middle are returned positive).
    RefMode::Begin:
        All returned offsets are relative to the begin of the frame border
        (lclGetBeg() always returns 0).
    RefMode::End:
        All returned offsets are relative to the end of the frame border
        (lclGetEnd() always returns 0).

                                                        |<- lclGetEnd()
                       |<- lclGetBeforeBeg()            |<- lclGetPrimEnd()
                       |                                |
                       ||<- lclGetBeg()                 ||<- lclGetBehindEnd()
                       ||                               ||
                       |#################################|
       direction of |   #################################
          the frame |   #################################
          border is |   #################################
           vertical |   #################################
                    v   #################################
                                        |
                                        |<- middle of the frame border

                                         lclGetDistEnd() ->||<- lclGetSecnBeg()
                                                           ||
          lclGetBeg() ->|   lclGetDistBeg() ->|            ||           |<- lclGetEnd()
                        |                     |            ||           |
    lclGetBeforeBeg()->||  lclGetPrimEnd() ->||            ||           ||<- lclGetBehindEnd()
                       ||                    ||            ||           ||
                       |######################|            |#############|
       direction of |   ######################              #############
          the frame |   ######################              #############
          border is |   ######################              #############
           vertical |   ######################  |           #############
                    v   ######################  |           #############
                        primary line            |           secondary line
                                                |
                                                |<- middle of the frame border

    @return
        The start offset of the single/primary line relative to the reference
        position of the frame border (sub units; 0 for invisible or one pixel
        wide single frame styles).
 */
long lclGetBeg( const Style& rBorder )
{
    long nPos = 0;
    switch( rBorder.GetRefMode() )
    {
        case RefMode::Centered:  if( rBorder.Prim() ) nPos = -128 * (rBorder.GetWidth() - 1); break;
        case RefMode::End:       if( rBorder.Prim() ) nPos = -256 * (rBorder.GetWidth() - 1); break;
        case RefMode::Begin:     break;
    }
    return nPos;
}

/** Returns the end offset of the single/secondary line across the frame border.
    @descr  See description of lclGetBeg() for an illustration.
    @return  The end offset of the single/secondary line relative to the
    reference position of the frame border (sub units; 0 for invisible or one
    pixel wide single frame styles). */
long lclGetEnd( const Style& rBorder )
{
    long nPos = 0;
    switch( rBorder.GetRefMode() )
    {
        case RefMode::Centered:  if( rBorder.Prim() ) nPos = 128 * (rBorder.GetWidth() - 1); break;
        case RefMode::Begin:     if( rBorder.Prim() ) nPos = 256 * (rBorder.GetWidth() - 1); break;
        case RefMode::End:     break;
    }
    return nPos;
}

/** Returns the end offset of the primary line across the frame border.
    @descr  See description of lclGetBeg() for an illustration.
    @return  The end offset of the primary line relative to the reference
    position of the frame border (sub units; the end of the primary line in a
    double frame style, otherwise the same as lclGetEnd()). */
inline long lclGetPrimEnd( const Style& rBorder )
{ return rBorder.Prim() ? (lclGetBeg( rBorder ) + 256 * (rBorder.Prim() - 1)) : 0; }

/** Returns the start offset of the secondary line across the frame border.
    @descr  See description of lclGetBeg() for an illustration.
    @return  The start offset of the secondary line relative to the reference
    position of the frame border (sub units; 0 for single/invisible border
    styles). */
inline long lclGetSecnBeg( const Style& rBorder )
{ return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * (rBorder.Secn() - 1)) : 0; }

/** Returns the start offset of the distance space across the frame border.
    @descr  See description of lclGetBeg() for an illustration.
    @return  The start offset of the distance space relative to the reference
    position of the frame border (sub units; 0 for single/invisible border
    styles). */
inline long lclGetDistBeg( const Style& rBorder )
{ return rBorder.Secn() ? (lclGetBeg( rBorder ) + 256 * rBorder.Prim()) : 0; }

/** Returns the end offset of the distance space across the frame border.
    @descr  See description of lclGetBeg() for an illustration.
    @return  The end offset of the distance space relative to the reference
    position of the frame border (sub units; 0 for single/invisible border
    styles). */
inline long lclGetDistEnd( const Style& rBorder )
{ return rBorder.Secn() ? (lclGetEnd( rBorder ) - 256 * rBorder.Secn()) : 0; }

/** Returns the offset before start of single/primary line across the frame border.
    @descr  See description of lclGetBeg() for an illustration.
    @return  The offset directly before start of single/primary line relative
    to the reference position of the frame border (sub units; a value one less
    than lclGetBeg() for visible frame styles, or 0 for invisible frame style). */
inline long lclGetBeforeBeg( const Style& rBorder )
{ return rBorder.Prim() ? (lclGetBeg( rBorder ) - 256) : 0; }

/** Returns the offset behind end of single/secondary line across the frame border.
    @descr  See description of lclGetBeg() for an illustration.
    @return  The offset directly behind end of single/secondary line relative
    to the reference position of the frame border (sub units; a value one
    greater than lclGetEnd() for visible frame styles, or 0 for invisible frame
    style). */
inline long lclGetBehindEnd( const Style& rBorder )
{ return rBorder.Prim() ? (lclGetEnd( rBorder ) + 256) : 0; }


// Linking functions


// Linking of single horizontal line ends.

/** Calculates X offsets for the left end of a single horizontal frame border.

    See DrawHorFrameBorder() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for the
        X coordinates of the left line end.
 */
void lclLinkLeftEnd_Single(
        LineEndResult& rResult, const Style& rBorder,
        const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
{
    // both vertical and diagonal frame borders are double
    if( rLFromT.Secn() && rLFromB.Secn() && rLFromTR.Secn() && rLFromBR.Secn() )
    {
        // take left position of upper and lower secondary start
        rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
        rResult.mnOffs2 = GetTLDiagOffset( lclGetEnd( rBorder ), lclGetSecnBeg( rLFromBR ), rLFromBR.GetAngle() );
    }
    else
    {
        // both vertical frame borders are double
        if( rLFromT.Secn() && rLFromB.Secn() )
        {
            rResult.mnOffs1 = (!rLFromTR.Secn() && !rLFromBR.Secn() && rtl::math::approxEqual(rLFromT.GetWidth(), rLFromB.GetWidth())) ?
                // don't overdraw vertical borders with equal width
                lclGetBehindEnd( rLFromT ) :
                // take leftmost start of both secondary lines (#46488#)
                std::min( lclGetSecnBeg( rLFromT ), lclGetSecnBeg( rLFromB ) );
        }

        // single border with equal width coming from left
        else if( !rLFromL.Secn() && rtl::math::approxEqual(rLFromL.Prim(), rBorder.Prim()) )
            // draw to connection point
            rResult.mnOffs1 = 0;

        // single border coming from left
        else if( !rLFromL.Secn() && rLFromL.Prim() )
        {
            if( rtl::math::approxEqual(rLFromL.Prim(), rBorder.Prim()) )
                // draw to reference position, if from left has equal width
                rResult.mnOffs1 = 0;
            else
                rResult.mnOffs1 = (rLFromL < rBorder) ?
                    // take leftmost start of both frame borders, if from left is thinner
                    std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
                    // do not overdraw vertical, if from left is thicker
                    std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );
        }

        // no border coming from left
        else if( !rLFromL.Prim() )
            // don't overdraw vertical borders with equal width
            rResult.mnOffs1 = rtl::math::approxEqual(rLFromT.GetWidth(), rLFromB.GetWidth()) ?
                lclGetBehindEnd( rLFromT ) :
                std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) );

        // double frame border coming from left and from top
        else if( rLFromT.Secn() )
            // do not overdraw the vertical double frame border
            rResult.mnOffs1 = lclGetBehindEnd( rLFromT );

        // double frame border coming from left and from bottom
        else if( rLFromB.Secn() )
            // do not overdraw the vertical double frame border
            rResult.mnOffs1 = lclGetBehindEnd( rLFromB );

        // double frame border coming from left, both vertical frame borders are single or off
        else
            // draw from leftmost start of both frame borders, if from left is not thicker
            rResult.mnOffs1 = (rLFromL <= rBorder) ?
                std::min( lclGetBeg( rLFromT ), lclGetBeg( rLFromB ) ) :
                std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );

        // bottom-left point is equal to top-left point (results in rectangle)
        rResult.mnOffs2 = rResult.mnOffs1;
    }
}

/** Calculates X offsets for the left end of a primary horizontal line.

    See DrawHorFrameBorder() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for the
        X coordinates of the left end of the primary line.
 */
void lclLinkLeftEnd_Prim(
        LineEndResult& rResult, const Style& rBorder,
        const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& /*rLFromBR*/ )
{
    // double diagonal frame border coming from top right
    if( rLFromTR.Secn() )
    {
        // draw from where secondary diagonal line meets the own primary
        rResult.mnOffs1 = GetBLDiagOffset( lclGetBeg( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
        rResult.mnOffs2 = GetBLDiagOffset( lclGetPrimEnd( rBorder ), lclGetSecnBeg( rLFromTR ), rLFromTR.GetAngle() );
    }

    // no or single diagonal frame border - ignore it
    else
    {
        // double frame border coming from top
        if( rLFromT.Secn() )
            // draw from left edge of secondary vertical
            rResult.mnOffs1 = lclGetSecnBeg( rLFromT );

        // double frame border coming from left (from top is not double)
        else if( rLFromL.Secn() )
            // do not overdraw single frame border coming from top
            rResult.mnOffs1 = rtl::math::approxEqual(rLFromL.GetWidth(), rBorder.GetWidth()) ?
                0 : lclGetBehindEnd( rLFromT );

        // double frame border coming from bottom (from top and from left are not double)
        else if( rLFromB.Secn() )
            // draw from left edge of primary vertical from bottom
            rResult.mnOffs1 = lclGetBeg( rLFromB );

        // no other frame border is double
        else
            // do not overdraw vertical frame borders
            rResult.mnOffs1 = std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );

        // bottom-left point is equal to top-left point (results in rectangle)
        rResult.mnOffs2 = rResult.mnOffs1;
    }
}

/** Calculates X offsets for the left end of a secondary horizontal line.

    See DrawHorFrameBorder() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for the
        X coordinates of the left end of the secondary line.
 */
void lclLinkLeftEnd_Secn(
        LineEndResult& rResult, const Style& rBorder,
        const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
{
    /*  Recycle lclLinkLeftEnd_Prim() function with mirrored horizontal borders. */
    lclLinkLeftEnd_Prim( rResult, rBorder.Mirror(), rLFromBR, rLFromB, rLFromL.Mirror(), rLFromT, rLFromTR );
    rResult.Swap();
}

void lclLinkLeftEnd_Gap(
        LineEndResult& rResult, const Style& rBorder,
        const DiagStyle& /*rLFromTR*/, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& /*rLFromBR*/ )

{
    if ( rLFromT.Secn() )
        rResult.mnOffs1 = lclGetDistBeg( rLFromT );
    else if ( rLFromL.Secn( ) )
        rResult.mnOffs1 = rtl::math::approxEqual( rLFromL.GetWidth(), rBorder.GetWidth() ) ?
            0 : lclGetBehindEnd( rLFromT );
    else if ( rLFromB.Secn( ) )
        rResult.mnOffs1 = lclGetDistBeg( rLFromB );
    else
        rResult.mnOffs1 = std::max( lclGetBehindEnd( rLFromT ), lclGetBehindEnd( rLFromB ) );

    rResult.mnOffs2 = rResult.mnOffs1;
}

// Linking of horizontal frame border ends.

/** Calculates X offsets for the left end of a horizontal frame border.

    This function can be used for single and double frame borders.
    See DrawHorFrameBorder() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for the
        X coordinates of the left end of the line(s) in the frame border.
 */
void lclLinkLeftEnd(
        BorderEndResult& rResult, const Style& rBorder,
        const DiagStyle& rLFromTR, const Style& rLFromT, const Style& rLFromL, const Style& rLFromB, const DiagStyle& rLFromBR )
{
    if( rBorder.Secn() )
    {
        // current frame border is double
        lclLinkLeftEnd_Prim( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
        lclLinkLeftEnd_Secn( rResult.maSecn, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
        lclLinkLeftEnd_Gap( rResult.maGap, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
    }
    else if( rBorder.Prim() )
    {
        // current frame border is single
        lclLinkLeftEnd_Single( rResult.maPrim, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
    }
    else
    {
        SAL_WARN( "svx.dialog", "lclLinkLeftEnd - called for invisible frame style" );
    }
}

/** Calculates X offsets for the right end of a horizontal frame border.

    This function can be used for single and double frame borders.
    See DrawHorFrameBorder() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for the
        X coordinates of the right end of the line(s) in the frame border.
 */
void lclLinkRightEnd(
        BorderEndResult& rResult, const Style& rBorder,
        const DiagStyle& rRFromTL, const Style& rRFromT, const Style& rRFromR, const Style& rRFromB, const DiagStyle& rRFromBL )
{
    /*  Recycle lclLinkLeftEnd() function with mirrored vertical borders. */
    lclLinkLeftEnd( rResult, rBorder, rRFromTL.Mirror(), rRFromT.Mirror(), rRFromR, rRFromB.Mirror(), rRFromBL.Mirror() );
    rResult.Negate();
}


// Linking of horizontal and vertical frame borders.

/** Calculates X offsets for all line ends of a horizontal frame border.

    This function can be used for single and double frame borders.
    See DrawHorFrameBorder() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for the
        X coordinates of both ends of the line(s) in the frame border. To get
        the actual X coordinates to draw the lines, these offsets have to be
        added to the X coordinates of the reference points of the frame border
        (the offsets may be negative).
 */
void lclLinkHorFrameBorder(
        BorderResult& rResult, 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 )
{
    lclLinkLeftEnd( rResult.maBeg, rBorder, rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR );
    lclLinkRightEnd( rResult.maEnd, rBorder, rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
}

/** Calculates Y offsets for all line ends of a vertical frame border.

    This function can be used for single and double frame borders.
    See DrawVerFrameBorder() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for the
        Y coordinates of both ends of the line(s) in the frame border. To get
        the actual Y coordinates to draw the lines, these offsets have to be
        added to the Y coordinates of the reference points of the frame border
        (the offsets may be negative).
 */
void lclLinkVerFrameBorder(
        BorderResult& rResult, const Style& rBorder,
        const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
        const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR )
{
    /*  Recycle lclLinkHorFrameBorder() function with correct parameters. The
        frame border is virtually mirrored at the top-left to bottom-right
        diagonal. rTFromBR and rBFromTL are mirrored to process their primary
        and secondary lines correctly. */
    lclLinkHorFrameBorder( rResult, rBorder,
        rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR.Mirror(),
        rBFromTL.Mirror(), rBFromL, rBFromB, rBFromR, rBFromTR );
}


// Linking of diagonal frame borders.

/** Calculates clipping offsets for a top-left to bottom-right frame border.

    This function can be used for single and double frame borders.
    See DrawDiagFrameBorders() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for all
        borders of the reference rectangle containing the diagonal frame border.
 */
void lclLinkTLBRFrameBorder(
        DiagBorderResult& rResult, const Style& rBorder,
        const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL )
{
    bool bIsDbl = rBorder.Secn() != 0;

    rResult.maPrim.mnLClip = lclGetBehindEnd( rTLFromB );
    rResult.maPrim.mnRClip = (bIsDbl && rBRFromT.Secn()) ? lclGetEnd( rBRFromT ) : lclGetBeforeBeg( rBRFromT );
    rResult.maPrim.mnTClip = (bIsDbl && rTLFromR.Secn()) ? lclGetBeg( rTLFromR ) : lclGetBehindEnd( rTLFromR );
    rResult.maPrim.mnBClip = lclGetBeforeBeg( rBRFromL );

    if( bIsDbl )
    {
        rResult.maSecn.mnLClip = rTLFromB.Secn() ? lclGetBeg( rTLFromB ) : lclGetBehindEnd( rTLFromB );
        rResult.maSecn.mnRClip = lclGetBeforeBeg( rBRFromT );
        rResult.maSecn.mnTClip = lclGetBehindEnd( rTLFromR );
        rResult.maSecn.mnBClip = rBRFromL.Secn() ? lclGetEnd( rBRFromL ) : lclGetBeforeBeg( rBRFromL );
    }
}

/** Calculates clipping offsets for a bottom-left to top-right frame border.

    This function can be used for single and double frame borders.
    See DrawDiagFrameBorders() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for all
        borders of the reference rectangle containing the diagonal frame border.
 */
void lclLinkBLTRFrameBorder(
        DiagBorderResult& rResult, const Style& rBorder,
        const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
{
    bool bIsDbl = rBorder.Secn() != 0;

    rResult.maPrim.mnLClip = lclGetBehindEnd( rBLFromT );
    rResult.maPrim.mnRClip = (bIsDbl && rTRFromB.Secn()) ? lclGetEnd( rTRFromB ) : lclGetBeforeBeg( rTRFromB );
    rResult.maPrim.mnTClip = lclGetBehindEnd( rTRFromL );
    rResult.maPrim.mnBClip = (bIsDbl && rBLFromR.Secn()) ? lclGetEnd( rBLFromR ) : lclGetBeforeBeg( rBLFromR );

    if( bIsDbl )
    {
        rResult.maSecn.mnLClip = rBLFromT.Secn() ? lclGetBeg( rBLFromT ) : lclGetBehindEnd( rBLFromT );
        rResult.maSecn.mnRClip = lclGetBeforeBeg( rTRFromB );
        rResult.maSecn.mnTClip = rTRFromL.Secn() ? lclGetBeg( rTRFromL ) : lclGetBehindEnd( rTRFromL );
        rResult.maSecn.mnBClip = lclGetBeforeBeg( rBLFromR );
    }
}

/** Calculates clipping offsets for both diagonal frame borders.

    This function can be used for single and double frame borders.
    See DrawDiagFrameBorders() function for a description of all parameters.

    @param rResult
        (out-param) The contained values (sub units) specify offsets for all
        borders of the reference rectangle containing the diagonal frame
        borders.
 */
void lclLinkDiagFrameBorders(
        DiagBordersResult& rResult, const Style& rTLBR, const Style& rBLTR,
        const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
        const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL )
{
    lclLinkTLBRFrameBorder( rResult.maTLBR, rTLBR, rTLFromB, rTLFromR, rBRFromT, rBRFromL );
    lclLinkBLTRFrameBorder( rResult.maBLTR, rBLTR, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
}


// Drawing functions


// Simple helper functions

/** Converts sub units to OutputDevice map units. */
inline long lclToMapUnit( long nSubUnits )
{
    return ((nSubUnits < 0) ? (nSubUnits - 127) : (nSubUnits + 128)) / 256;
}

/** Converts a point in sub units to an OutputDevice point. */
inline Point lclToMapUnit( long nSubXPos, long nSubYPos )
{
    return Point( lclToMapUnit( nSubXPos ), lclToMapUnit( nSubYPos ) );
}

/** Returns a polygon constructed from a vector of points. */
inline tools::Polygon lclCreatePolygon( const PointVec& rPoints )
{
    return tools::Polygon( static_cast< sal_uInt16 >( rPoints.size() ), &rPoints[ 0 ] );
}

/** Returns a polygon constructed from the five passed points. */
vcl::Region lclCreatePolygon( const Point& rP1, const Point& rP2, const Point& rP3, const Point& rP4, const Point& rP5 )
{
    PointVec aPoints;
    aPoints.reserve( 5 );
    aPoints.push_back( rP1 );
    aPoints.push_back( rP2 );
    aPoints.push_back( rP3 );
    aPoints.push_back( rP4 );
    aPoints.push_back( rP5 );
    return vcl::Region(lclCreatePolygon(aPoints));
}

/** Sets the color of the passed frame style to the output device.

    Sets the line color and fill color in the output device.

    @param rDev
        The output device the color has to be set to. The old colors are pushed
        onto the device's stack and can be restored with a call to
        OutputDevice::Pop(). Please take care about the correct calling order
        of Pop() if this function is used with other functions pushing
        something onto the stack.
    @param rStyle
        The border style that contains the line color to be set to the device.
 */
void lclSetColorToOutDev( OutputDevice& rDev, const Color& rColor, const Color* pForceColor )
{
    rDev.Push( PushFlags::LINECOLOR | PushFlags::FILLCOLOR );
    rDev.SetLineColor( pForceColor ? *pForceColor : rColor );
    rDev.SetFillColor( pForceColor ? *pForceColor : rColor );
}


// Drawing of horizontal frame borders.

/** Draws a horizontal thin or thick line into the passed output device.

    The X coordinates of the edges of the line are adjusted according to the
    passed LineEndResult structs. A one pixel wide line can be drawn dotted.
 */
void lclDrawHorLine(
        OutputDevice& rDev,
        const Point& rLPos, const LineEndResult& rLRes,
        const Point& rRPos, const LineEndResult& rRRes,
        long nTOffs, long nBOffs, SvxBorderLineStyle nDashing )
{
    LinePoints aTPoints( rLPos + lclToMapUnit( rLRes.mnOffs1, nTOffs ), rRPos + lclToMapUnit( rRRes.mnOffs1, nTOffs ) );
    LinePoints aBPoints( rLPos + lclToMapUnit( rLRes.mnOffs2, nBOffs ), rRPos + lclToMapUnit( rRRes.mnOffs2, nBOffs ) );

    sal_uInt32 nWidth = lclToMapUnit( std::abs( nTOffs ) ) + lclToMapUnit( std::abs( nBOffs ) );
    if ( ( nTOffs >= 0 && nBOffs >= 0 ) || ( nTOffs <= 0 && nBOffs <= 0 ) )
        nWidth = std::abs( lclToMapUnit( nTOffs ) - lclToMapUnit( nBOffs ) ) + 1;
    Point rLMid = ( aTPoints.maBeg + aBPoints.maBeg ) / 2;
    Point rRMid = ( aTPoints.maEnd + aBPoints.maEnd ) / 2;

    ::svtools::DrawLine( rDev, rLMid, rRMid, nWidth, nDashing );
}

/** Draws a horizontal frame border into the passed output device.

    @param rLPos
        The top-left or bottom-left reference point of the diagonal frame border.
    @param rRPos
        The top-right or bottom-right reference point of the diagonal frame border.
    @param rBorder
        The frame style used to draw the border.
    @param rResult
        The X coordinates of the edges of all lines of the frame border are
        adjusted according to the offsets contained here.
 */
void lclDrawHorFrameBorder(
        OutputDevice& rDev, const Point& rLPos, const Point& rRPos,
        const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
{
    DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawHorFrameBorder - line not visible" );
    DBG_ASSERT( rLPos.X() <= rRPos.X(), "svx::frame::lclDrawHorFrameBorder - wrong order of line ends" );
    DBG_ASSERT( rLPos.Y() == rRPos.Y(), "svx::frame::lclDrawHorFrameBorder - line not horizontal" );
    if( rLPos.X() <= rRPos.X() )
    {
        if ( rBorder.UseGapColor( ) )
        {
            lclSetColorToOutDev( rDev, rBorder.GetColorGap(), pForceColor );
            lclDrawHorLine( rDev, rLPos, rResult.maBeg.maGap, rRPos, rResult.maEnd.maGap,
                   lclGetPrimEnd( rBorder ), lclGetSecnBeg( rBorder ), rBorder.Type() );
            rDev.Pop(); // Gap color
        }

        lclSetColorToOutDev( rDev, rBorder.GetColorPrim(), pForceColor );
        lclDrawHorLine( rDev, rLPos, rResult.maBeg.maPrim, rRPos, rResult.maEnd.maPrim,
            lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Type() );
        rDev.Pop(); // colors

        if( rBorder.Secn() )
        {
            lclSetColorToOutDev( rDev, rBorder.GetColorSecn(), pForceColor );
            lclDrawHorLine( rDev, rLPos, rResult.maBeg.maSecn, rRPos, rResult.maEnd.maSecn,
                lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Type() );
            rDev.Pop(); // colors
        }
    }
}


// Drawing of vertical frame borders.

/** Draws a vertical thin or thick line into the passed output device.

    The Y coordinates of the edges of the line are adjusted according to the
    passed LineEndResult structs. A one pixel wide line can be drawn dotted.
 */
void lclDrawVerLine(
        OutputDevice& rDev,
        const Point& rTPos, const LineEndResult& rTRes,
        const Point& rBPos, const LineEndResult& rBRes,
        long nLOffs, long nROffs, SvxBorderLineStyle nDashing )
{
    LinePoints aLPoints( rTPos + lclToMapUnit( nLOffs, rTRes.mnOffs1 ), rBPos + lclToMapUnit( nLOffs, rBRes.mnOffs1 ) );
    LinePoints aRPoints( rTPos + lclToMapUnit( nROffs, rTRes.mnOffs2 ), rBPos + lclToMapUnit( nROffs, rBRes.mnOffs2 ) );

    sal_uInt32 nWidth = lclToMapUnit( std::abs( nLOffs ) ) + lclToMapUnit( std::abs( nROffs ) );
    if ( ( nLOffs >= 0 && nROffs >= 0 ) || ( nLOffs <= 0 && nROffs <= 0 ) )
        nWidth = std::abs( lclToMapUnit( nLOffs ) - lclToMapUnit( nROffs ) ) + 1;
    Point rTMid = ( aLPoints.maBeg + aRPoints.maBeg ) / 2;
    Point rBMid = ( aLPoints.maEnd + aRPoints.maEnd ) / 2;

    ::svtools::DrawLine( rDev, rTMid, rBMid, nWidth, nDashing );
}

/** Draws a vertical frame border into the passed output device.

    @param rTPos
        The top-left or top-right reference point of the diagonal frame border.
    @param rBPos
        The bottom-left or bottom-right reference point of the diagonal frame border.
    @param rBorder
        The frame style used to draw the border.
    @param rResult
        The Y coordinates of the edges of all lines of the frame border are
        adjusted according to the offsets contained here.
 */
void lclDrawVerFrameBorder(
        OutputDevice& rDev, const Point& rTPos, const Point& rBPos,
        const Style& rBorder, const BorderResult& rResult, const Color* pForceColor )
{
    DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawVerFrameBorder - line not visible" );
    DBG_ASSERT( rTPos.Y() <= rBPos.Y(), "svx::frame::lclDrawVerFrameBorder - wrong order of line ends" );
    DBG_ASSERT( rTPos.X() == rBPos.X(), "svx::frame::lclDrawVerFrameBorder - line not vertical" );
    if( rTPos.Y() <= rBPos.Y() )
    {
        if ( rBorder.UseGapColor( ) )
        {
            lclSetColorToOutDev( rDev, rBorder.GetColorGap(), pForceColor );
            lclDrawVerLine( rDev, rTPos, rResult.maBeg.maGap, rBPos, rResult.maEnd.maGap,
                   lclGetPrimEnd( rBorder ), lclGetSecnBeg( rBorder ), rBorder.Type() );
            rDev.Pop(); // Gap color
        }

        lclSetColorToOutDev( rDev, rBorder.GetColorPrim(), pForceColor );
        lclDrawVerLine( rDev, rTPos, rResult.maBeg.maPrim, rBPos, rResult.maEnd.maPrim,
            lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Type() );
        rDev.Pop(); // colors
        if( rBorder.Secn() )
        {
            lclSetColorToOutDev( rDev, rBorder.GetColorSecn(), pForceColor );
            lclDrawVerLine( rDev, rTPos, rResult.maBeg.maSecn, rBPos, rResult.maEnd.maSecn,
                lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Type() );
            rDev.Pop(); // colors
        }
    }
}


// Drawing of diagonal frame borders, includes clipping functions.

/** Returns the drawing coordinates for a diagonal thin line.

    This function can be used for top-left to bottom-right and for bottom-left
    to top-right lines.

    @param rRect
        The reference rectangle of the diagonal frame border.
    @param bTLBR
        true = top-left to bottom-right; false = bottom-left to top-right.
    @param nDiagOffs
        Width offset (sub units) across the diagonal frame border.
    @return
        A struct containg start and end position of the diagonal line.
 */
LinePoints lclGetDiagLineEnds( const tools::Rectangle& rRect, bool bTLBR, long nDiagOffs )
{
    LinePoints aPoints( rRect, bTLBR );
    bool bVert = rRect.GetWidth() < rRect.GetHeight();
    double fAngle = bVert ? GetVerDiagAngle( rRect ) : GetHorDiagAngle( rRect );
    // vertical top-left to bottom-right borders are handled mirrored
    if( bVert && bTLBR )
        nDiagOffs = -nDiagOffs;
    long nTOffs = bTLBR ? GetTLDiagOffset( 0, nDiagOffs, fAngle ) : GetTRDiagOffset( nDiagOffs, fAngle );
    long nBOffs = bTLBR ? GetBRDiagOffset( nDiagOffs, fAngle ) : GetBLDiagOffset( 0, nDiagOffs, fAngle );
    // vertical bottom-left to top-right borders are handled with exchanged end points
    if( bVert && !bTLBR )
        std::swap( nTOffs, nBOffs );
    (bVert ? aPoints.maBeg.Y() : aPoints.maBeg.X()) += lclToMapUnit( nTOffs );
    (bVert ? aPoints.maEnd.Y() : aPoints.maEnd.X()) += lclToMapUnit( nBOffs );
    return aPoints;
}


// Clipping functions for diagonal frame borders.

/** Limits the clipping region to the inner area of a rectangle.

    Takes the values from the passed DiagLineResult struct into account. They
    may specify to not clip one or more borders of a rectangle.

    @param rDev
        The output device with the clipping region to be modified. The old
        clipping region is pushed onto the device's stack and can be restored
        with a call to OutputDevice::Pop(). Please take care about the correct
        calling order of Pop() if this function is used with other functions
        pushing something onto the stack.
    @param rRect
        The reference rectangle of the diagonal frame borders.
    @param rResult
        The result struct containing modifies for each border of the reference
        rectangle.
 */
void lclPushDiagClipRect( OutputDevice& rDev, const tools::Rectangle& rRect, const DiagLineResult& rResult )
{
    // PixelToLogic() regards internal offset of the output device
    tools::Rectangle aClipRect( rRect );
    aClipRect.Left()   += lclToMapUnit( rResult.mnLClip );
    aClipRect.Top()    += lclToMapUnit( rResult.mnTClip );
    aClipRect.Right()  += lclToMapUnit( rResult.mnRClip );
    aClipRect.Bottom() += lclToMapUnit( rResult.mnBClip );
    // output device would adjust the rectangle -> invalidate it before
    if( (aClipRect.GetWidth() < 1) ||(aClipRect.GetHeight() < 1) )
        aClipRect.SetEmpty();

    rDev.Push( PushFlags::CLIPREGION );
    rDev.IntersectClipRegion( aClipRect );
}

/** Excludes inner area of a crossing double frame border from clipping region.

    This function is used to modify the clipping region so that it excludes the
    inner free area of a double diagonal frame border. This makes it possible
    to draw a diagonal frame border in one step without taking care of the
    crossing double frame border.

    @param rDev
        The output device with the clipping region to be modified. The old
        clipping region is pushed onto the device's stack and can be restored
        with a call to OutputDevice::Pop(). Please take care about the correct
        calling order of Pop() if this function is used with other functions
        pushing something onto the stack.
    @param rRect
        The reference rectangle of the diagonal frame borders.
    @param bTLBR
        The orientation of the processed frame border (not the orientation of
        the crossing frame border).
    @param bCrossStyle
        The style of the crossing frame border. Must be a double frame style.
 */
void lclPushCrossingClipRegion( OutputDevice& rDev, const tools::Rectangle& rRect, bool bTLBR, const Style& rCrossStyle )
{
    DBG_ASSERT( rCrossStyle.Secn(), "lclGetCrossingClipRegion - use only for double styles" );
    LinePoints aLPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetPrimEnd( rCrossStyle ) ) );
    LinePoints aRPoints( lclGetDiagLineEnds( rRect, !bTLBR, lclGetSecnBeg( rCrossStyle ) ) );

    vcl::Region aClipReg;
    if( bTLBR )
    {
        aClipReg = lclCreatePolygon(
            aLPoints.maBeg, aLPoints.maEnd, rRect.BottomRight(), rRect.BottomLeft(), rRect.TopLeft() );
        aClipReg.Union( lclCreatePolygon(
            aRPoints.maBeg, aRPoints.maEnd, rRect.BottomRight(), rRect.TopRight(), rRect.TopLeft() ) );
    }
    else
    {
        aClipReg = lclCreatePolygon(
            aLPoints.maBeg, aLPoints.maEnd, rRect.BottomLeft(), rRect.TopLeft(), rRect.TopRight() );
        aClipReg.Union( lclCreatePolygon(
            aRPoints.maBeg, aRPoints.maEnd, rRect.BottomLeft(), rRect.BottomRight(), rRect.TopRight() ) );
    }

    rDev.Push( PushFlags::CLIPREGION );
    rDev.IntersectClipRegion( aClipReg );
}


// Drawing functions for diagonal frame borders.

/** Draws a diagonal thin or thick line into the passed output device.

    The clipping region of the output device is modified according to the
    passed DiagLineResult struct. A one pixel wide line can be drawn dotted.
 */
void lclDrawDiagLine(
        OutputDevice& rDev, const tools::Rectangle& rRect, bool bTLBR,
        const DiagLineResult& rResult, long nDiagOffs1, long nDiagOffs2, SvxBorderLineStyle nDashing )
{
    lclPushDiagClipRect( rDev, rRect, rResult );
    LinePoints aLPoints( lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs1 ) );
    LinePoints aL2Points( lclGetDiagLineEnds( rRect, bTLBR, nDiagOffs2 ) );
    Point aSMid( ( aLPoints.maBeg + aL2Points.maBeg ) / 2 );
    Point aEMid( ( aLPoints.maEnd + aL2Points.maEnd ) / 2 );

    sal_uInt32 nWidth = lclToMapUnit( std::abs( nDiagOffs1 ) ) + lclToMapUnit( std::abs( nDiagOffs2 ) );
    if ( ( nDiagOffs1 <= 0 && nDiagOffs2 <= 0 ) || ( nDiagOffs1 >=0 && nDiagOffs2 >=0 ) )
        nWidth = lclToMapUnit( std::abs( nDiagOffs1 - nDiagOffs2 ) );

    svtools::DrawLine( rDev, aSMid, aEMid, nWidth, nDashing );
    rDev.Pop(); // clipping region
}

/** Draws a diagonal frame border into the passed output device.

    The lines of the frame border are drawn interrupted, if the style of the
    crossing frame border is double.

    @param rRect
        The reference rectangle of the diagonal frame border.
    @param bTLBR
        The orientation of the diagonal frame border.
    @param rBorder
        The frame style used to draw the border.
    @param rResult
        Offsets (sub units) to modify the clipping region of the output device.
    @param rCrossStyle
        Style of the crossing diagonal frame border.
 */
void lclDrawDiagFrameBorder(
        OutputDevice& rDev, const tools::Rectangle& rRect, bool bTLBR,
        const Style& rBorder, const DiagBorderResult& rResult, const Style& rCrossStyle,
        const Color* pForceColor, bool bDiagDblClip )
{
    DBG_ASSERT( rBorder.Prim(), "svx::frame::lclDrawDiagFrameBorder - line not visible" );

    bool bClip = bDiagDblClip && rCrossStyle.Secn();
    if( bClip )
        lclPushCrossingClipRegion( rDev, rRect, bTLBR, rCrossStyle );

    lclSetColorToOutDev( rDev, rBorder.GetColorPrim(), pForceColor );
    lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maPrim, lclGetBeg( rBorder ), lclGetPrimEnd( rBorder ), rBorder.Type() );
    rDev.Pop(); // colors
    if( rBorder.Secn() )
    {
        if ( rBorder.UseGapColor( ) )
        {
            lclSetColorToOutDev( rDev, rBorder.GetColorGap(), pForceColor );
            lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maSecn, lclGetDistBeg( rBorder ), lclGetDistEnd( rBorder ), rBorder.Type() );
            rDev.Pop(); // colors
        }

        lclSetColorToOutDev( rDev, rBorder.GetColorSecn(), pForceColor );
        lclDrawDiagLine( rDev, rRect, bTLBR, rResult.maSecn, lclGetSecnBeg( rBorder ), lclGetEnd( rBorder ), rBorder.Type() );
        rDev.Pop(); // colors
    }

    if( bClip )
        rDev.Pop(); // clipping region
}

/** Draws both diagonal frame borders into the passed output device.

    The lines of each frame border is drawn interrupted, if the style of the
    other crossing frame border is double.

    @param rRect
        The reference rectangle of the diagonal frame borders.
    @param rTLBR
        The frame style of the top-left to bottom-right frame border.
    @param rBLTR
        The frame style of the bottom-left to top-right frame border.
    @param rResult
        Offsets (sub units) to modify the clipping region of the output device.
 */
void lclDrawDiagFrameBorders(
        OutputDevice& rDev, const tools::Rectangle& rRect,
        const Style& rTLBR, const Style& rBLTR, const DiagBordersResult& rResult,
        const Color* pForceColor, bool bDiagDblClip )
{
    DBG_ASSERT( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1), "svx::frame::lclDrawDiagFrameBorders - rectangle too small" );
    if( (rRect.GetWidth() > 1) && (rRect.GetHeight() > 1) )
    {
        bool bDrawTLBR = rTLBR.Prim() != 0;
        bool bDrawBLTR = rBLTR.Prim() != 0;
        bool bFirstDrawBLTR = rTLBR.Secn() != 0;

        if( bDrawBLTR && bFirstDrawBLTR )
            lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
        if( bDrawTLBR )
            lclDrawDiagFrameBorder( rDev, rRect, true, rTLBR, rResult.maTLBR, rBLTR, pForceColor, bDiagDblClip );
        if( bDrawBLTR && !bFirstDrawBLTR )
            lclDrawDiagFrameBorder( rDev, rRect, false, rBLTR, rResult.maBLTR, rTLBR, pForceColor, bDiagDblClip );
    }
}


} // namespace


@@ -1121,7 +67,8 @@ void lclDrawDiagFrameBorders(
Style::Style() :
    meRefMode(RefMode::Centered),
    mfPatternScale(1.0),
    mnType(SvxBorderLineStyle::SOLID)
    mnType(SvxBorderLineStyle::SOLID),
    mpUsingCell(nullptr)
{
    Clear();
}
@@ -1129,7 +76,8 @@ Style::Style() :
Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType ) :
    meRefMode(RefMode::Centered),
    mfPatternScale(1.0),
    mnType(nType)
    mnType(nType),
    mpUsingCell(nullptr)
{
    Clear();
    Set( nP, nD, nS );
@@ -1139,14 +87,16 @@ Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rCo
              double nP, double nD, double nS, SvxBorderLineStyle nType ) :
    meRefMode(RefMode::Centered),
    mfPatternScale(1.0),
    mnType(nType)
    mnType(nType),
    mpUsingCell(nullptr)
{
    Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS );
}

Style::Style( const editeng::SvxBorderLine* pBorder, double fScale ) :
    meRefMode(RefMode::Centered),
    mfPatternScale(fScale)
    mfPatternScale(fScale),
    mpUsingCell(nullptr)
{
    Set( pBorder, fScale );
}
@@ -1293,35 +243,16 @@ bool operator<( const Style& rL, const Style& rR )


// Various helper functions


double GetHorDiagAngle( long nWidth, long nHeight )
{
    return atan2( static_cast< double >( std::abs( nHeight ) ), static_cast< double >( std::abs( nWidth ) ) );
}


long GetTLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
{
    return lclD2L( nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
}

long GetBLDiagOffset( long nVerOffs, long nDiagOffs, double fAngle )
{
    return lclD2L( -nVerOffs / tan( fAngle ) + nDiagOffs / sin( fAngle ) );
}

long GetBRDiagOffset( long nDiagOffs, double fAngle )
{
    return -lclD2L( - nDiagOffs / sin( fAngle ) );
}

long GetTRDiagOffset( long nDiagOffs, double fAngle )
{
    return -lclD2L( - nDiagOffs / sin( fAngle ) );
}


bool CheckFrameBorderConnectable( const Style& rLBorder, const Style& rRBorder,
        const Style& rTFromTL, const Style& rTFromT, const Style& rTFromTR,
        const Style& rBFromBL, const Style& rBFromB, const Style& rBFromBR )
@@ -1347,7 +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)
{
@@ -1417,8 +347,9 @@ double lcl_GetExtent(

void CreateBorderPrimitives(
    drawinglayer::primitive2d::Primitive2DContainer& rTarget,
    const Point& rLPos,
    const Point& rRPos,
    const basegfx::B2DPoint& rOrigin,
    const basegfx::B2DVector& rX,
    const basegfx::B2DVector& rY,
    const Style& rBorder,
    const DiagStyle& /*rLFromTR*/,
    const Style& rLFromT,
@@ -1430,14 +361,14 @@ void CreateBorderPrimitives(
    const Style& /*rRFromR*/,
    const Style& rRFromB,
    const DiagStyle& /*rRFromBL*/,
    const Color* /*pForceColor*/,
    const long nRotateT,
    const long nRotateB)
    const Color* pForceColor)
{
    if (rBorder.Prim() || rBorder.Secn())
    {
        basegfx::B2DPoint aStart(rLPos.getX(), rLPos.getY());
        basegfx::B2DPoint aEnd(rRPos.getX(), rRPos.getY());
        basegfx::B2DPoint aStart(rOrigin);
        basegfx::B2DPoint aEnd(rOrigin + rX);
        const long nRotateT = 9000; /// Angle of the top slanted frames in 100th of degree
        const long nRotateB = 9000; /// Angle of the bottom slanted frames in 100th of degree

        rTarget.append(
            drawinglayer::primitive2d::Primitive2DReference(
@@ -1450,17 +381,18 @@ void CreateBorderPrimitives(
                    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(),
                    (pForceColor ? *pForceColor : rBorder.GetColorSecn()).getBColor(),
                    (pForceColor ? *pForceColor : rBorder.GetColorPrim()).getBColor(),
                    (pForceColor ? *pForceColor : rBorder.GetColorGap()).getBColor(),
                    rBorder.UseGapColor(), rBorder.Type(), rBorder.PatternScale())));
    }
}

void CreateBorderPrimitives(
    drawinglayer::primitive2d::Primitive2DContainer& rTarget,
    const Point& rLPos,
    const Point& rRPos,
    const basegfx::B2DPoint& rOrigin,
    const basegfx::B2DVector& rX,
    const basegfx::B2DVector& rY,
    const Style& rBorder,
    const Style& rLFromT,
    const Style& rLFromL,
@@ -1468,16 +400,15 @@ void CreateBorderPrimitives(
    const Style& rRFromT,
    const Style& rRFromR,
    const Style& rRFromB,
    const Color* pForceColor,
    const long nRotateT,
    const long nRotateB)
    const Color* pForceColor)
{
    if (rBorder.Prim() || rBorder.Secn())
    {
        CreateBorderPrimitives(
            rTarget,
            rLPos,
            rRPos,
            rOrigin,
            rX,
            rY,
            rBorder,
            DiagStyle(),
            rLFromT,
@@ -1489,15 +420,15 @@ void CreateBorderPrimitives(
            rRFromR,
            rRFromB,
            DiagStyle(),
            pForceColor,
            nRotateT,
            nRotateB);
            pForceColor);
    }
}

void CreateDiagFrameBorderPrimitives(
    drawinglayer::primitive2d::Primitive2DContainer& rTarget,
    const basegfx::B2DRange& rRange,
    const basegfx::B2DPoint& rOrigin,
    const basegfx::B2DVector& rXAxis,
    const basegfx::B2DVector& rYAxis,
    const Style& rTLBR,
    const Style& rBLTR,
    const Style& rTLFromB,
@@ -1508,23 +439,25 @@ void CreateDiagFrameBorderPrimitives(
    const Style& rBLFromR,
    const Style& rTRFromB,
    const Style& rTRFromL,
    const Color* /*pForceColor*/,
    const long /*nRotationT*/,
    const long /*nRotationB*/)
    const Color* pForceColor)
{
    if (rTLBR.Prim())
    {
        // top-left to bottom-right
        rTarget.append(
            new drawinglayer::primitive2d::BorderLinePrimitive2D(
                rRange.getMinimum(),
                rRange.getMaximum(),
                rOrigin,
                rOrigin + rXAxis + rYAxis,
                rTLBR.Prim(),
                rTLBR.Dist(),
                rTLBR.Secn(),
                0.0, 0.0, 0.0, 0.0,
                rTLBR.GetColorSecn().getBColor(),
                rTLBR.GetColorPrim().getBColor(),
                rTLBR.GetColorGap().getBColor(),
                0.0,
                0.0,
                0.0,
                0.0,
                (pForceColor ? *pForceColor : rTLBR.GetColorSecn()).getBColor(),
                (pForceColor ? *pForceColor : rTLBR.GetColorPrim()).getBColor(),
                (pForceColor ? *pForceColor : rTLBR.GetColorGap()).getBColor(),
                rTLBR.UseGapColor(),
                rTLBR.Type(),
                rTLBR.PatternScale()));
@@ -1532,73 +465,26 @@ void CreateDiagFrameBorderPrimitives(

    if (rBLTR.Prim())
    {
        // bottom-left to top-right
        rTarget.append(
            new drawinglayer::primitive2d::BorderLinePrimitive2D(
                basegfx::B2DPoint(rRange.getMinX(), rRange.getMaxY()),
                basegfx::B2DPoint(rRange.getMaxX(), rRange.getMinY()),
                rOrigin + rYAxis,
                rOrigin + rXAxis,
                rBLTR.Prim(),
                rBLTR.Dist(),
                rBLTR.Secn(),
                0.0, 0.0, 0.0, 0.0,
                rBLTR.GetColorSecn().getBColor(),
                rBLTR.GetColorPrim().getBColor(),
                rBLTR.GetColorGap().getBColor(),
                0.0,
                0.0,
                0.0,
                0.0,
                (pForceColor ? *pForceColor : rBLTR.GetColorSecn()).getBColor(),
                (pForceColor ? *pForceColor : rBLTR.GetColorPrim()).getBColor(),
                (pForceColor ? *pForceColor : rBLTR.GetColorGap()).getBColor(),
                rBLTR.UseGapColor(),
                rBLTR.Type(),
                rBLTR.PatternScale()));
    }
}

void DrawHorFrameBorder( OutputDevice& rDev,
        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 )
{
    if( rBorder.Prim() )
    {
        BorderResult aResult;
        lclLinkHorFrameBorder( aResult, rBorder,
            rLFromTR, rLFromT, rLFromL, rLFromB, rLFromBR,
            rRFromTL, rRFromT, rRFromR, rRFromB, rRFromBL );
        lclDrawHorFrameBorder( rDev, rLPos, rRPos, rBorder, aResult, pForceColor );
    }
}


void DrawVerFrameBorder( OutputDevice& rDev,
        const Point& rTPos, const Point& rBPos, const Style& rBorder,
        const DiagStyle& rTFromBL, const Style& rTFromL, const Style& rTFromT, const Style& rTFromR, const DiagStyle& rTFromBR,
        const DiagStyle& rBFromTL, const Style& rBFromL, const Style& rBFromB, const Style& rBFromR, const DiagStyle& rBFromTR,
        const Color* pForceColor )
{
    if( rBorder.Prim() )
    {
        BorderResult aResult;
        lclLinkVerFrameBorder( aResult, rBorder,
            rTFromBL, rTFromL, rTFromT, rTFromR, rTFromBR,
            rBFromTL, rBFromL, rBFromB, rBFromR, rBFromTR );
        lclDrawVerFrameBorder( rDev, rTPos, rBPos, rBorder, aResult, pForceColor );
    }
}


void DrawDiagFrameBorders(
        OutputDevice& rDev, const tools::Rectangle& rRect, const Style& rTLBR, const Style& rBLTR,
        const Style& rTLFromB, const Style& rTLFromR, const Style& rBRFromT, const Style& rBRFromL,
        const Style& rBLFromT, const Style& rBLFromR, const Style& rTRFromB, const Style& rTRFromL,
        const Color* pForceColor, bool bDiagDblClip )
{
    if( rTLBR.Prim() || rBLTR.Prim() )
    {
        DiagBordersResult aResult;
        lclLinkDiagFrameBorders( aResult, rTLBR, rBLTR,
            rTLFromB, rTLFromR, rBRFromT, rBRFromL, rBLFromT, rBLFromR, rTRFromB, rTRFromL );
        lclDrawDiagFrameBorders( rDev, rRect, rTLBR, rBLTR, aResult, pForceColor, bDiagDblClip );
    }
}


}
}

diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index 09f4e3a..839e9be 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -28,25 +28,52 @@
namespace svx {
namespace frame {

struct Cell
/// single exclusive friend method to change mpUsingCell at style when style
/// is set at Cell, see friend definition for more info
void exclusiveSetUsigCellAtStyle(Style& rStyle, const Cell* pCell) { rStyle.mpUsingCell = pCell; }

class Cell
{
private:
    Style               maLeft;
    Style               maRight;
    Style               maTop;
    Style               maBottom;
    Style               maTLBR;
    Style               maBLTR;

public:
    long                mnAddLeft;
    long                mnAddRight;
    long                mnAddTop;
    long                mnAddBottom;

    SvxRotateMode       meRotMode;
    double              mfOrientation;

    bool                mbMergeOrig;
    bool                mbOverlapX;
    bool                mbOverlapY;

public:
    explicit            Cell();

    bool         IsMerged() const { return mbMergeOrig || mbOverlapX || mbOverlapY; }
    void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; exclusiveSetUsigCellAtStyle(maLeft, this); }
    void SetStyleRight(const Style& rStyle) { maRight = rStyle; exclusiveSetUsigCellAtStyle(maRight, this); }
    void SetStyleTop(const Style& rStyle) { maTop = rStyle; exclusiveSetUsigCellAtStyle(maTop, this); }
    void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; exclusiveSetUsigCellAtStyle(maBottom, this); }
    void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; exclusiveSetUsigCellAtStyle(maTLBR, this); }
    void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; exclusiveSetUsigCellAtStyle(maBLTR, this); }

    const Style& GetStyleLeft() const { return maLeft; }
    const Style& GetStyleRight() const { return maRight; }
    const Style& GetStyleTop() const { return maTop; }
    const Style& GetStyleBottom() const { return maBottom; }
    const Style& GetStyleTLBR() const { return maTLBR; }
    const Style& GetStyleBLTR() const { return maBLTR; }

    bool                IsMerged() const { return mbMergeOrig || mbOverlapX || mbOverlapY; }
    bool                IsRotated() const { return mfOrientation != 0.0; }

    void                MirrorSelfX();
};
@@ -59,6 +86,8 @@ Cell::Cell() :
    mnAddRight( 0 ),
    mnAddTop( 0 ),
    mnAddBottom( 0 ),
    meRotMode(SvxRotateMode::SVX_ROTATE_MODE_STANDARD ),
    mfOrientation( 0.0 ),
    mbMergeOrig( false ),
    mbOverlapX( false ),
    mbOverlapY( false )
@@ -71,6 +100,7 @@ void Cell::MirrorSelfX()
    std::swap( mnAddLeft, mnAddRight );
    maLeft.MirrorSelf();
    maRight.MirrorSelf();
    mfOrientation = -mfOrientation;
}


@@ -119,9 +149,9 @@ struct ArrayImpl
    size_t              mnLastClipRow;
    mutable bool        mbXCoordsDirty;
    mutable bool        mbYCoordsDirty;
    bool                mbDiagDblClip;
    bool                mbMayHaveCellRotation;

    explicit            ArrayImpl( size_t nWidth, size_t nHeight, bool bDiagDblClip );
    explicit            ArrayImpl( size_t nWidth, size_t nHeight );

    bool         IsValidPos( size_t nCol, size_t nRow ) const
                            { return (nCol < mnWidth) && (nRow < mnHeight); }
@@ -157,9 +187,11 @@ struct ArrayImpl

    double              GetHorDiagAngle( size_t nCol, size_t nRow ) const;
    double              GetVerDiagAngle( size_t nCol, size_t nRow ) const;

    bool                HasCellRotation() const;
};

ArrayImpl::ArrayImpl( size_t nWidth, size_t nHeight, bool bDiagDblClip ) :
ArrayImpl::ArrayImpl( size_t nWidth, size_t nHeight ) :
    mnWidth( nWidth ),
    mnHeight( nHeight ),
    mnFirstClipCol( 0 ),
@@ -168,7 +200,7 @@ ArrayImpl::ArrayImpl( size_t nWidth, size_t nHeight, bool bDiagDblClip ) :
    mnLastClipRow( nHeight - 1 ),
    mbXCoordsDirty( false ),
    mbYCoordsDirty( false ),
    mbDiagDblClip( bDiagDblClip )
    mbMayHaveCellRotation( false )
{
    // default-construct all vectors
    maCells.resize( mnWidth * mnHeight );
@@ -318,6 +350,19 @@ double ArrayImpl::GetVerDiagAngle( size_t nCol, size_t nRow ) const
    return (fAngle > 0.0) ? (F_PI2 - fAngle) : 0.0;
}

bool ArrayImpl::HasCellRotation() const
{
    // check cell array
    for (const auto& aCell : maCells)
    {
        if (aCell.IsRotated())
        {
            return true;
        }
    }

    return false;
}

class MergedCellIterator
{
@@ -385,8 +430,7 @@ Array::~Array()
// array size and column/row indexes
void Array::Initialize( size_t nWidth, size_t nHeight )
{
    bool bDiagDblClip = mxImpl.get() ? mxImpl->mbDiagDblClip : DIAG_DBL_CLIP_DEFAULT;
    mxImpl.reset( new ArrayImpl( nWidth, nHeight, bDiagDblClip ) );
    mxImpl.reset( new ArrayImpl( nWidth, nHeight ) );
}

size_t Array::GetColCount() const
@@ -416,45 +460,45 @@ size_t Array::GetCellIndex( size_t nCol, size_t nRow, bool bRTL ) const
void Array::SetCellStyleLeft( size_t nCol, size_t nRow, const Style& rStyle )
{
    DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleLeft" );
    CELLACC( nCol, nRow ).maLeft = rStyle;
    CELLACC( nCol, nRow ).SetStyleLeft(rStyle);
}

void Array::SetCellStyleRight( size_t nCol, size_t nRow, const Style& rStyle )
{
    DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleRight" );
    CELLACC( nCol, nRow ).maRight = rStyle;
    CELLACC( nCol, nRow ).SetStyleRight(rStyle);
}

void Array::SetCellStyleTop( size_t nCol, size_t nRow, const Style& rStyle )
{
    DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTop" );
    CELLACC( nCol, nRow ).maTop = rStyle;
    CELLACC( nCol, nRow ).SetStyleTop(rStyle);
}

void Array::SetCellStyleBottom( size_t nCol, size_t nRow, const Style& rStyle )
{
    DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBottom" );
    CELLACC( nCol, nRow ).maBottom = rStyle;
    CELLACC( nCol, nRow ).SetStyleBottom(rStyle);
}

void Array::SetCellStyleTLBR( size_t nCol, size_t nRow, const Style& rStyle )
{
    DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleTLBR" );
    CELLACC( nCol, nRow ).maTLBR = rStyle;
    CELLACC( nCol, nRow ).SetStyleTLBR(rStyle);
}

void Array::SetCellStyleBLTR( size_t nCol, size_t nRow, const Style& rStyle )
{
    DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleBLTR" );
    CELLACC( nCol, nRow ).maBLTR = rStyle;
    CELLACC( nCol, nRow ).SetStyleBLTR(rStyle);
}

void Array::SetCellStyleDiag( size_t nCol, size_t nRow, const Style& rTLBR, const Style& rBLTR )
{
    DBG_FRAME_CHECK_COLROW( nCol, nRow, "SetCellStyleDiag" );
    Cell& rCell = CELLACC( nCol, nRow );
    rCell.maTLBR = rTLBR;
    rCell.maBLTR = rBLTR;
    rCell.SetStyleTLBR(rTLBR);
    rCell.SetStyleBLTR(rBLTR);
}

void Array::SetColumnStyleLeft( size_t nCol, const Style& rStyle )
@@ -485,6 +529,32 @@ void Array::SetRowStyleBottom( size_t nRow, const Style& rStyle )
        SetCellStyleBottom( nCol, nRow, rStyle );
}

void Array::SetCellRotation(size_t nCol, size_t nRow, SvxRotateMode eRotMode, double fOrientation)
{
    DBG_FRAME_CHECK_COLROW(nCol, nRow, "SetCellRotation");
    Cell& rTarget = CELLACC(nCol, nRow);
    rTarget.meRotMode = eRotMode;
    rTarget.mfOrientation = fOrientation;

    if (!mxImpl->mbMayHaveCellRotation)
    {
        // activate once when a cell gets actually rotated to allow fast
        // answering HasCellRotation() calls
        mxImpl->mbMayHaveCellRotation = rTarget.IsRotated();
    }
}

bool Array::HasCellRotation() const
{
    if (!mxImpl->mbMayHaveCellRotation)
    {
        // never set, no need to check
        return false;
    }

    return mxImpl->HasCellRotation();
}

const Style& Array::GetCellStyleLeft( size_t nCol, size_t nRow ) const
{
    // outside clipping rows or overlapped in merged cells: invisible
@@ -492,15 +562,15 @@ const Style& Array::GetCellStyleLeft( size_t nCol, size_t nRow ) const
        return OBJ_STYLE_NONE;
    // left clipping border: always own left style
    if( nCol == mxImpl->mnFirstClipCol )
        return ORIGCELL( nCol, nRow ).maLeft;
        return ORIGCELL( nCol, nRow ).GetStyleLeft();
    // right clipping border: always right style of left neighbor cell
    if( nCol == mxImpl->mnLastClipCol + 1 )
        return ORIGCELL( nCol - 1, nRow ).maRight;
        return ORIGCELL( nCol - 1, nRow ).GetStyleRight();
    // outside clipping columns: invisible
    if( !mxImpl->IsColInClipRange( nCol ) )
        return OBJ_STYLE_NONE;
    // inside clipping range: maximum of own left style and right style of left neighbor cell
    return std::max( ORIGCELL( nCol, nRow ).maLeft, ORIGCELL( nCol - 1, nRow ).maRight );
    return std::max( ORIGCELL( nCol, nRow ).GetStyleLeft(), ORIGCELL( nCol - 1, nRow ).GetStyleRight() );
}

const Style& Array::GetCellStyleRight( size_t nCol, size_t nRow ) const
@@ -510,15 +580,15 @@ const Style& Array::GetCellStyleRight( size_t nCol, size_t nRow ) const
        return OBJ_STYLE_NONE;
    // left clipping border: always left style of right neighbor cell
    if( nCol + 1 == mxImpl->mnFirstClipCol )
        return ORIGCELL( nCol + 1, nRow ).maLeft;
        return ORIGCELL( nCol + 1, nRow ).GetStyleLeft();
    // right clipping border: always own right style
    if( nCol == mxImpl->mnLastClipCol )
        return ORIGCELL( nCol, nRow ).maRight;
        return ORIGCELL( nCol, nRow ).GetStyleRight();
    // outside clipping columns: invisible
    if( !mxImpl->IsColInClipRange( nCol ) )
        return OBJ_STYLE_NONE;
    // inside clipping range: maximum of own right style and left style of right neighbor cell
    return std::max( ORIGCELL( nCol, nRow ).maRight, ORIGCELL( nCol + 1, nRow ).maLeft );
    return std::max( ORIGCELL( nCol, nRow ).GetStyleRight(), ORIGCELL( nCol + 1, nRow ).GetStyleLeft() );
}

const Style& Array::GetCellStyleTop( size_t nCol, size_t nRow ) const
@@ -528,15 +598,15 @@ const Style& Array::GetCellStyleTop( size_t nCol, size_t nRow ) const
        return OBJ_STYLE_NONE;
    // top clipping border: always own top style
    if( nRow == mxImpl->mnFirstClipRow )
        return ORIGCELL( nCol, nRow ).maTop;
        return ORIGCELL( nCol, nRow ).GetStyleTop();
    // bottom clipping border: always bottom style of top neighbor cell
    if( nRow == mxImpl->mnLastClipRow + 1 )
        return ORIGCELL( nCol, nRow - 1 ).maBottom;
        return ORIGCELL( nCol, nRow - 1 ).GetStyleBottom();
    // outside clipping rows: invisible
    if( !mxImpl->IsRowInClipRange( nRow ) )
        return OBJ_STYLE_NONE;
    // inside clipping range: maximum of own top style and bottom style of top neighbor cell
    return std::max( ORIGCELL( nCol, nRow ).maTop, ORIGCELL( nCol, nRow - 1 ).maBottom );
    return std::max( ORIGCELL( nCol, nRow ).GetStyleTop(), ORIGCELL( nCol, nRow - 1 ).GetStyleBottom() );
}

const Style& Array::GetCellStyleBottom( size_t nCol, size_t nRow ) const
@@ -546,25 +616,25 @@ const Style& Array::GetCellStyleBottom( size_t nCol, size_t nRow ) const
        return OBJ_STYLE_NONE;
    // top clipping border: always top style of bottom neighbor cell
    if( nRow + 1 == mxImpl->mnFirstClipRow )
        return ORIGCELL( nCol, nRow + 1 ).maTop;
        return ORIGCELL( nCol, nRow + 1 ).GetStyleTop();
    // bottom clipping border: always own bottom style
    if( nRow == mxImpl->mnLastClipRow )
        return ORIGCELL( nCol, nRow ).maBottom;
        return ORIGCELL( nCol, nRow ).GetStyleBottom();
    // outside clipping rows: invisible
    if( !mxImpl->IsRowInClipRange( nRow ) )
        return OBJ_STYLE_NONE;
    // inside clipping range: maximum of own bottom style and top style of bottom neighbor cell
    return std::max( ORIGCELL( nCol, nRow ).maBottom, ORIGCELL( nCol, nRow + 1 ).maTop );
    return std::max( ORIGCELL( nCol, nRow ).GetStyleBottom(), ORIGCELL( nCol, nRow + 1 ).GetStyleTop() );
}

const Style& Array::GetCellStyleTLBR( size_t nCol, size_t nRow ) const
{
    return CELL( nCol, nRow ).maTLBR;
    return CELL( nCol, nRow ).GetStyleTLBR();
}

const Style& Array::GetCellStyleBLTR( size_t nCol, size_t nRow ) const
{
    return CELL( nCol, nRow ).maBLTR;
    return CELL( nCol, nRow ).GetStyleBLTR();
}

const Style& Array::GetCellStyleTL( size_t nCol, size_t nRow ) const
@@ -576,7 +646,7 @@ const Style& Array::GetCellStyleTL( size_t nCol, size_t nRow ) const
    size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
    size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
    return ((nCol == nFirstCol) && (nRow == nFirstRow)) ?
        CELL( nFirstCol, nFirstRow ).maTLBR : OBJ_STYLE_NONE;
        CELL( nFirstCol, nFirstRow ).GetStyleTLBR() : OBJ_STYLE_NONE;
}

const Style& Array::GetCellStyleBR( size_t nCol, size_t nRow ) const
@@ -588,7 +658,7 @@ const Style& Array::GetCellStyleBR( size_t nCol, size_t nRow ) const
    size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
    size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
    return ((nCol == nLastCol) && (nRow == nLastRow)) ?
        CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).maTLBR : OBJ_STYLE_NONE;
        CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleTLBR() : OBJ_STYLE_NONE;
}

const Style& Array::GetCellStyleBL( size_t nCol, size_t nRow ) const
@@ -600,7 +670,7 @@ const Style& Array::GetCellStyleBL( size_t nCol, size_t nRow ) const
    size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
    size_t nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );
    return ((nCol == nFirstCol) && (nRow == nLastRow)) ?
        CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).maBLTR : OBJ_STYLE_NONE;
        CELL( nFirstCol, mxImpl->GetMergedFirstRow( nCol, nRow ) ).GetStyleBLTR() : OBJ_STYLE_NONE;
}

const Style& Array::GetCellStyleTR( size_t nCol, size_t nRow ) const
@@ -612,7 +682,7 @@ const Style& Array::GetCellStyleTR( size_t nCol, size_t nRow ) const
    size_t nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
    size_t nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
    return ((nCol == nLastCol) && (nRow == nFirstRow)) ?
        CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).maBLTR : OBJ_STYLE_NONE;
        CELL( mxImpl->GetMergedFirstCol( nCol, nRow ), nFirstRow ).GetStyleBLTR() : OBJ_STYLE_NONE;
}

// cell merging
@@ -709,15 +779,6 @@ void Array::SetClipRange( size_t nFirstCol, size_t nFirstRow, size_t nLastCol, s
    mxImpl->mnLastClipRow = nLastRow;
}

tools::Rectangle Array::GetClipRangeRectangle() const
{
    return tools::Rectangle(
        mxImpl->GetColPosition( mxImpl->mnFirstClipCol ),
        mxImpl->GetRowPosition( mxImpl->mnFirstClipRow ),
        mxImpl->GetColPosition( mxImpl->mnLastClipCol + 1 ),
        mxImpl->GetRowPosition( mxImpl->mnLastClipRow + 1 ) );
}

// cell coordinates
void Array::SetXOffset( long nXOffset )
{
@@ -838,11 +899,6 @@ double Array::GetVerDiagAngle( size_t nCol, size_t nRow ) const
    return mxImpl->GetVerDiagAngle( nCol, nRow );
}

void Array::SetUseDiagDoubleClipping( bool bSet )
{
    mxImpl->mbDiagDblClip = bSet;
}

// mirroring
void Array::MirrorSelfX()
{
@@ -879,6 +935,46 @@ void Array::MirrorSelfX()
}

// drawing

void CreateCoordinateSystemForCell(
    const basegfx::B2DRange& rRange,
    const Cell& rCell,
    basegfx::B2DPoint& rOrigin,
    basegfx::B2DVector& rX,
    basegfx::B2DVector& rY)
{
    // fill in defaults
    rOrigin = rRange.getMinimum();
    rX = basegfx::B2DVector(rRange.getWidth(), 0.0);
    rY = basegfx::B2DVector(0.0, rRange.getHeight());

    if (rCell.IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != rCell.meRotMode)
    {
        // when rotated, adapt values. Get Skew (cos/sin == 1/tan)
        const double fSkew(rRange.getHeight() * (cos(rCell.mfOrientation) / sin(rCell.mfOrientation)));

        switch (rCell.meRotMode)
        {
        case SvxRotateMode::SVX_ROTATE_MODE_TOP:
            // shear Y-Axis
            rY.setX(-fSkew);
            break;
        case SvxRotateMode::SVX_ROTATE_MODE_CENTER:
            // shear origin half, Y full
            rOrigin.setX(rOrigin.getX() + (fSkew * 0.5));
            rY.setX(-fSkew);
            break;
        case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM:
            // shear origin full, Y full
            rOrigin.setX(rOrigin.getX() + fSkew);
            rY.setX(-fSkew);
            break;
        default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, altready excluded above
            break;
        }
    }
}

void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
        size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow,
        const Color* pForceColor ) const
@@ -898,10 +994,11 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
            bool bOverlapY = rCell.mbOverlapY;
            bool bFirstCol = nCol == nFirstCol;
            bool bFirstRow = nRow == nFirstRow;
            if ((!bOverlapX && !bOverlapY) || (bFirstCol && bFirstRow) ||
                (!bOverlapY && bFirstCol) || (!bOverlapX && bFirstRow))

            if ((!bOverlapX && !bOverlapY) || (bFirstCol && bFirstRow) || (!bOverlapY && bFirstCol) || (!bOverlapX && bFirstRow))
            {
                const tools::Rectangle aRect(GetCellRect(nCol, nRow));

                if ((aRect.GetWidth() > 1) && (aRect.GetHeight() > 1))
                {
                    size_t _nFirstCol = mxImpl->GetMergedFirstCol(nCol, nRow);
@@ -915,10 +1012,17 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                    {
                        drawinglayer::primitive2d::Primitive2DContainer aSequence;
                        const basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());
                        basegfx::B2DPoint aOrigin;
                        basegfx::B2DVector aX;
                        basegfx::B2DVector aY;

                        CreateCoordinateSystemForCell(aRange, rCell, aOrigin, aX, aY);

                        CreateDiagFrameBorderPrimitives(
                            aSequence,
                            aRange,
                            aOrigin,
                            aX,
                            aY,
                            rTLBR,
                            rBLTR,
                            GetCellStyleLeft(_nFirstCol, _nFirstRow),
@@ -929,7 +1033,7 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                            GetCellStyleBottom(_nFirstCol, _nLastRow),
                            GetCellStyleRight(_nLastCol, _nFirstRow),
                            GetCellStyleTop(_nLastCol, _nFirstRow),
                            nullptr);
                            pForceColor);

                        rProcessor.process(aSequence);
                    }
@@ -945,7 +1049,7 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
        double fTAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow - 1 );

        // *Start*** variables store the data of the left end of the cached frame border
        Point aStartPos( mxImpl->GetColPosition( nFirstCol ), mxImpl->GetRowPosition( nRow ) );
        basegfx::B2DPoint aStartPos( mxImpl->GetColPosition( nFirstCol ), mxImpl->GetRowPosition( nRow ) );
        const Style* pStart = &GetCellStyleTop( nFirstCol, nRow );
        DiagStyle aStartLFromTR( GetCellStyleBL( nFirstCol, nRow - 1 ), fTAngle );
        const Style* pStartLFromT = &GetCellStyleLeft( nFirstCol, nRow - 1 );
@@ -980,18 +1084,50 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
            DiagStyle aRFromBL( GetCellStyleTR( nCol, nRow ), fAngle );

            // check if current frame border can be connected to cached frame border
            if( !CheckFrameBorderConnectable( *pStart, rCurr,
                    aEndRFromTL, rLFromT, aLFromTR, aEndRFromBL, rLFromB, aLFromBR ) )
            if( !CheckFrameBorderConnectable( *pStart, rCurr, aEndRFromTL, rLFromT, aLFromTR, aEndRFromBL, rLFromB, aLFromBR ) )
            {
                // draw previous frame border
                Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
                if ((pStart->Prim() || pStart->Secn()) && (aStartPos.X() <= aEndPos.X()))
                basegfx::B2DPoint aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.getY() );

                if ((pStart->Prim() || pStart->Secn()) && (aStartPos.getX() <= aEndPos.getX()))
                {
                    // prepare defaults for borderline coordinate system
                    basegfx::B2DPoint aOrigin(aStartPos);
                    basegfx::B2DVector aX(aEndPos - aStartPos);
                    basegfx::B2DVector aY(0.0, 1.0);
                    const Cell* pCell = pStart->GetUsingCell();

                    if (pCell && pCell->IsRotated())
                    {
                        // To apply the shear, we need to get the cell range. We have the defining cell,
                        // but there is no call at it to directly get it's range. To get the correct one,
                        // we need to take care if the borderline is at top or bottom, so use pointer
                        // compare here to find out
                        const bool bUpper(&pCell->GetStyleTop() == pStart);
                        const tools::Rectangle aRect(GetCellRect(nCol - 1, bUpper ? nRow : nRow - 1));
                        const basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());

                        // adapt to cell coordinate system, including shear
                        CreateCoordinateSystemForCell(aRange, *pCell, aOrigin, aX, aY);

                        if (!bUpper)
                        {
                            // for the lower edge we need to translate to get to the
                            // borderline coordinate system. For the upper one, all is
                            // okay already
                            aOrigin  += aY;
                        }

                        // borderline coordinate system uses normalized 2nd axis
                        aY.normalize();
                    }

                    drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                    CreateBorderPrimitives(
                        aSequence,
                        aStartPos,
                        aEndPos,
                        aOrigin,
                        aX,
                        aY,
                        *pStart,
                        aStartLFromTR,
                        *pStartLFromT,
@@ -1026,14 +1162,38 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
        }

        // draw last frame border
        Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
        if ((pStart->Prim() || pStart->Secn()) && (aStartPos.X() <= aEndPos.X()))
        basegfx::B2DPoint aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.getY() );
        if ((pStart->Prim() || pStart->Secn()) && (aStartPos.getX() <= aEndPos.getX()))
        {
            // for description of involved coordinate systems have a look at
            // the first CreateBorderPrimitives call above
            basegfx::B2DPoint aOrigin(aStartPos);
            basegfx::B2DVector aX(aEndPos - aStartPos);
            basegfx::B2DVector aY(0.0, 1.0);
            const Cell* pCell = pStart->GetUsingCell();

            if (pCell && pCell->IsRotated())
            {
                const bool bUpper(&pCell->GetStyleTop() == pStart);
                const tools::Rectangle aRect(GetCellRect(nCol - 1, bUpper ? nRow : nRow - 1));
                const basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());

                CreateCoordinateSystemForCell(aRange, *pCell, aOrigin, aX, aY);

                if (!bUpper)
                {
                    aOrigin += aY;
                }

                aY.normalize();
            }

            drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
            CreateBorderPrimitives(
                aSequence,
                aStartPos,
                aEndPos,
                aOrigin,
                aX,
                aY,
                *pStart,
                aStartLFromTR,
                *pStartLFromT,
@@ -1057,7 +1217,7 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
        double fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nFirstRow );

        // *Start*** variables store the data of the top end of the cached frame border
        Point aStartPos( mxImpl->GetColPosition( nCol ), mxImpl->GetRowPosition( nFirstRow ) );
        basegfx::B2DPoint aStartPos( mxImpl->GetColPosition( nCol ), mxImpl->GetRowPosition( nFirstRow ) );
        const Style* pStart = &GetCellStyleLeft( nCol, nFirstRow );
        DiagStyle aStartTFromBL( GetCellStyleTR( nCol - 1, nFirstRow ), fLAngle );
        const Style* pStartTFromL = &GetCellStyleTop( nCol - 1, nFirstRow );
@@ -1096,9 +1256,38 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                    aEndBFromTL, rTFromL, aTFromBL, aEndBFromTR, rTFromR, aTFromBR ) )
            {
                // draw previous frame border
                Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
                if ((pStart->Prim() || pStart->Secn()) && (aStartPos.Y() <= aEndPos.Y()))
                basegfx::B2DPoint aEndPos( aStartPos.getX(), mxImpl->GetRowPosition( nRow ) );
                if ((pStart->Prim() || pStart->Secn()) && (aStartPos.getY() <= aEndPos.getY()))
                {
                    // for description of involved coordinate systems have a look at
                    // the first CreateBorderPrimitives call above. Additionally adapt to vertical
                    basegfx::B2DPoint aOrigin(aStartPos);
                    basegfx::B2DVector aX(aEndPos - aStartPos);
                    basegfx::B2DVector aY(-1.0, 0.0);
                    const Cell* pCell = pStart->GetUsingCell();

                    if (pCell && pCell->IsRotated())
                    {
                        const bool bLeft(&pCell->GetStyleLeft() == pStart);
                        const tools::Rectangle aRect(GetCellRect(bLeft ? nCol : nCol - 1, nRow - 1));
                        const basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());

                        CreateCoordinateSystemForCell(aRange, *pCell, aOrigin, aX, aY);

                        if (!bLeft)
                        {
                            aOrigin += aX;
                        }

                        // The *coordinate system* of the edge has to be given, which for vertical
                        // lines uses the Y-Vector as X-Axis and the X-Vector as Y-Axis, so swap both
                        // and mirror aX to keep the same orientation (should be (-1.0, 0.0) for
                        // horizontal lines anyways, this could be used as thest here, checked in debug mode)
                        std::swap(aX, aY);
                        aY.normalize();
                        aY = -aY;
                    }

                    drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
                    CreateBorderPrimitives(
                        // This replaces DrawVerFrameBorder which went from top to bottom. To be able to use
@@ -1108,10 +1297,11 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                        // 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
                        // lines.
                        aSequence,
                        aStartPos,
                        aEndPos,
                        aOrigin,
                        aX,
                        aY,
                        *pStart,
                        aStartTFromBR,
                        *pStartTFromR,
@@ -1146,15 +1336,44 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
        }

        // draw last frame border
        Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
        if ((pStart->Prim() || pStart->Secn()) && (aStartPos.Y() <= aEndPos.Y()))
        basegfx::B2DPoint aEndPos( aStartPos.getX(), mxImpl->GetRowPosition( nRow ) );
        if ((pStart->Prim() || pStart->Secn()) && (aStartPos.getY() <= aEndPos.getY()))
        {
            // for description of involved coordinate systems have a look at
            // the first CreateBorderPrimitives call above, adapt to vertical
            basegfx::B2DPoint aOrigin(aStartPos);
            basegfx::B2DVector aX(aEndPos - aStartPos);
            basegfx::B2DVector aY(-1.0, 0.0);
            const Cell* pCell = pStart->GetUsingCell();

            if (pCell && pCell->IsRotated())
            {
                const bool bLeft(&pCell->GetStyleLeft() == pStart);
                const tools::Rectangle aRect(GetCellRect(bLeft ? nCol : nCol - 1, nRow - 1));
                const basegfx::B2DRange aRange(aRect.Left(), aRect.Top(), aRect.Right(), aRect.Bottom());

                CreateCoordinateSystemForCell(aRange, *pCell, aOrigin, aX, aY);

                if (!bLeft)
                {
                    aOrigin += aX;
                }

                // The *coordinate system* of the edge has to be given, which for vertical
                // lines uses the Y-Vector as X-Axis and the X-Vector as Y-Axis, so swap both
                // and mirror aX to keep the same orientation (should be (-1.0, 0.0) for horizontal lines anyways)
                std::swap(aX, aY);
                aY.normalize();
                aY = -aY;
            }

            drawinglayer::primitive2d::Primitive2DContainer aSequence(1);
            CreateBorderPrimitives(
                // also reordered, see call to CreateBorderPrimitives above
                aSequence,
                aStartPos,
                aEndPos,
                aOrigin,
                aX,
                aY,
                *pStart,
                aStartTFromBR,
                *pStartTFromR,
@@ -1172,224 +1391,12 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
    }
}

void Array::DrawRange( OutputDevice& rDev,
        size_t nFirstCol, size_t nFirstRow, size_t nLastCol, size_t nLastRow ) const
{
    DBG_FRAME_CHECK_COLROW( nFirstCol, nFirstRow, "DrawRange" );
    DBG_FRAME_CHECK_COLROW( nLastCol, nLastRow, "DrawRange" );

    size_t nCol, nRow;

    // *** diagonal frame borders ***

    // set clipping region to clip partly visible merged cells
    rDev.Push( PushFlags::CLIPREGION );
    rDev.IntersectClipRegion( GetClipRangeRectangle() );
    for( nRow = nFirstRow; nRow <= nLastRow; ++nRow )
    {
        for( nCol = nFirstCol; nCol <= nLastCol; ++nCol )
        {
            const Cell& rCell = CELL( nCol, nRow );
            bool bOverlapX = rCell.mbOverlapX;
            bool bOverlapY = rCell.mbOverlapY;
            bool bFirstCol = nCol == nFirstCol;
            bool bFirstRow = nRow == nFirstRow;
            if( (!bOverlapX && !bOverlapY) || (bFirstCol && bFirstRow) ||
                (!bOverlapY && bFirstCol) || (!bOverlapX && bFirstRow) )
            {
                tools::Rectangle aRect( GetCellRect( nCol, nRow ) );
                if( (aRect.GetWidth() > 1) && (aRect.GetHeight() > 1) )
                {
                    size_t _nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
                    size_t _nFirstRow = mxImpl->GetMergedFirstRow( nCol, nRow );
                    size_t _nLastCol = mxImpl->GetMergedLastCol( nCol, nRow );
                    size_t _nLastRow = mxImpl->GetMergedLastRow( nCol, nRow );

                    DrawDiagFrameBorders( rDev, aRect,
                        GetCellStyleTLBR( _nFirstCol, _nFirstRow ), GetCellStyleBLTR( _nFirstCol, _nFirstRow ),
                        GetCellStyleLeft( _nFirstCol, _nFirstRow ), GetCellStyleTop( _nFirstCol, _nFirstRow ),
                        GetCellStyleRight( _nLastCol, _nLastRow ), GetCellStyleBottom( _nLastCol, _nLastRow ),
                        GetCellStyleLeft( _nFirstCol, _nLastRow ), GetCellStyleBottom( _nFirstCol, _nLastRow ),
                        GetCellStyleRight( _nLastCol, _nFirstRow ), GetCellStyleTop( _nLastCol, _nFirstRow ),
                        nullptr, mxImpl->mbDiagDblClip );
                }
            }
        }
    }
    rDev.Pop(); // clip region

    // *** horizontal frame borders ***

    for( nRow = nFirstRow; nRow <= nLastRow + 1; ++nRow )
    {
        double fAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow );
        double fTAngle = mxImpl->GetHorDiagAngle( nFirstCol, nRow - 1 );

        // *Start*** variables store the data of the left end of the cached frame border
        Point aStartPos( mxImpl->GetColPosition( nFirstCol ), mxImpl->GetRowPosition( nRow ) );
        const Style* pStart = &GetCellStyleTop( nFirstCol, nRow );
        DiagStyle aStartLFromTR( GetCellStyleBL( nFirstCol, nRow - 1 ), fTAngle );
        const Style* pStartLFromT = &GetCellStyleLeft( nFirstCol, nRow - 1 );
        const Style* pStartLFromL = &GetCellStyleTop( nFirstCol - 1, nRow );
        const Style* pStartLFromB = &GetCellStyleLeft( nFirstCol, nRow );
        DiagStyle aStartLFromBR( GetCellStyleTL( nFirstCol, nRow ), fAngle );

        // *End*** variables store the data of the right end of the cached frame border
        DiagStyle aEndRFromTL( GetCellStyleBR( nFirstCol, nRow - 1 ), fTAngle );
        const Style* pEndRFromT = &GetCellStyleRight( nFirstCol, nRow - 1 );
        const Style* pEndRFromR = &GetCellStyleTop( nFirstCol + 1, nRow );
        const Style* pEndRFromB = &GetCellStyleRight( nFirstCol, nRow );
        DiagStyle aEndRFromBL( GetCellStyleTR( nFirstCol, nRow ), fAngle );

        for( nCol = nFirstCol + 1; nCol <= nLastCol; ++nCol )
        {
            fAngle = mxImpl->GetHorDiagAngle( nCol, nRow );
            fTAngle = mxImpl->GetHorDiagAngle( nCol, nRow - 1 );

            const Style& rCurr = *pEndRFromR;

            DiagStyle aLFromTR( GetCellStyleBL( nCol, nRow - 1 ), fTAngle );
            const Style& rLFromT = *pEndRFromT;
            const Style& rLFromL = *pStart;
            const Style& rLFromB = *pEndRFromB;
            DiagStyle aLFromBR( GetCellStyleTL( nCol, nRow ), fAngle );

            DiagStyle aRFromTL( GetCellStyleBR( nCol, nRow - 1 ), fTAngle );
            const Style& rRFromT = GetCellStyleRight( nCol, nRow - 1 );
            const Style& rRFromR = GetCellStyleTop( nCol + 1, nRow );
            const Style& rRFromB = GetCellStyleRight( nCol, nRow );
            DiagStyle aRFromBL( GetCellStyleTR( nCol, nRow ), fAngle );

            // check if current frame border can be connected to cached frame border
            if( !CheckFrameBorderConnectable( *pStart, rCurr,
                    aEndRFromTL, rLFromT, aLFromTR, aEndRFromBL, rLFromB, aLFromBR ) )
            {
                // draw previous frame border
                Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
                if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) )
                    DrawHorFrameBorder( rDev, aStartPos, aEndPos, *pStart,
                        aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR,
                        aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL );

                // re-init "*Start***" variables
                aStartPos = aEndPos;
                pStart = &rCurr;
                aStartLFromTR = aLFromTR;
                pStartLFromT = &rLFromT;
                pStartLFromL = &rLFromL;
                pStartLFromB = &rLFromB;
                aStartLFromBR = aLFromBR;
            }

            // store current styles in "*End***" variables
            aEndRFromTL = aRFromTL;
            pEndRFromT = &rRFromT;
            pEndRFromR = &rRFromR;
            pEndRFromB = &rRFromB;
            aEndRFromBL = aRFromBL;
        }

        // draw last frame border
        Point aEndPos( mxImpl->GetColPosition( nCol ), aStartPos.Y() );
        if( pStart->Prim() && (aStartPos.X() <= aEndPos.X()) )
            DrawHorFrameBorder( rDev, aStartPos, aEndPos, *pStart,
                aStartLFromTR, *pStartLFromT, *pStartLFromL, *pStartLFromB, aStartLFromBR,
                aEndRFromTL, *pEndRFromT, *pEndRFromR, *pEndRFromB, aEndRFromBL );
    }

    // *** vertical frame borders ***

    for( nCol = nFirstCol; nCol <= nLastCol + 1; ++nCol )
    {
        double fAngle = mxImpl->GetVerDiagAngle( nCol, nFirstRow );
        double fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nFirstRow );

        // *Start*** variables store the data of the top end of the cached frame border
        Point aStartPos( mxImpl->GetColPosition( nCol ), mxImpl->GetRowPosition( nFirstRow ) );
        const Style* pStart = &GetCellStyleLeft( nCol, nFirstRow );
        DiagStyle aStartTFromBL( GetCellStyleTR( nCol - 1, nFirstRow ), fLAngle );
        const Style* pStartTFromL = &GetCellStyleTop( nCol - 1, nFirstRow );
        const Style* pStartTFromT = &GetCellStyleLeft( nCol, nFirstRow - 1 );
        const Style* pStartTFromR = &GetCellStyleTop( nCol, nFirstRow );
        DiagStyle aStartTFromBR( GetCellStyleTL( nCol, nFirstRow ), fAngle );

        // *End*** variables store the data of the bottom end of the cached frame border
        DiagStyle aEndBFromTL( GetCellStyleBR( nCol - 1, nFirstRow ), fLAngle );
        const Style* pEndBFromL = &GetCellStyleBottom( nCol - 1, nFirstRow );
        const Style* pEndBFromB = &GetCellStyleLeft( nCol, nFirstRow + 1 );
        const Style* pEndBFromR = &GetCellStyleBottom( nCol, nFirstRow );
        DiagStyle aEndBFromTR( GetCellStyleBL( nCol, nFirstRow ), fAngle );

        for( nRow = nFirstRow + 1; nRow <= nLastRow; ++nRow )
        {
            fAngle = mxImpl->GetVerDiagAngle( nCol, nRow );
            fLAngle = mxImpl->GetVerDiagAngle( nCol - 1, nRow );

            const Style& rCurr = *pEndBFromB;

            DiagStyle aTFromBL( GetCellStyleTR( nCol - 1, nRow ), fLAngle );
            const Style& rTFromL = *pEndBFromL;
            const Style& rTFromT = *pStart;
            const Style& rTFromR = *pEndBFromR;
            DiagStyle aTFromBR( GetCellStyleTL( nCol, nRow ), fAngle );

            DiagStyle aBFromTL( GetCellStyleBR( nCol - 1, nRow ), fLAngle );
            const Style& rBFromL = GetCellStyleBottom( nCol - 1, nRow );
            const Style& rBFromB = GetCellStyleLeft( nCol, nRow + 1 );
            const Style& rBFromR = GetCellStyleBottom( nCol, nRow );
            DiagStyle aBFromTR( GetCellStyleBL( nCol, nRow ), fAngle );

            // check if current frame border can be connected to cached frame border
            if( !CheckFrameBorderConnectable( *pStart, rCurr,
                    aEndBFromTL, rTFromL, aTFromBL, aEndBFromTR, rTFromR, aTFromBR ) )
            {
                // draw previous frame border
                Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
                if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) )
                    DrawVerFrameBorder( rDev, aStartPos, aEndPos, *pStart,
                        aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR,
                        aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR );

                // re-init "*Start***" variables
                aStartPos = aEndPos;
                pStart = &rCurr;
                aStartTFromBL = aTFromBL;
                pStartTFromL = &rTFromL;
                pStartTFromT = &rTFromT;
                pStartTFromR = &rTFromR;
                aStartTFromBR = aTFromBR;
            }

            // store current styles in "*End***" variables
            aEndBFromTL = aBFromTL;
            pEndBFromL = &rBFromL;
            pEndBFromB = &rBFromB;
            pEndBFromR = &rBFromR;
            aEndBFromTR = aBFromTR;
        }

        // draw last frame border
        Point aEndPos( aStartPos.X(), mxImpl->GetRowPosition( nRow ) );
        if( pStart->Prim() && (aStartPos.Y() <= aEndPos.Y()) )
            DrawVerFrameBorder( rDev, aStartPos, aEndPos, *pStart,
                aStartTFromBL, *pStartTFromL, *pStartTFromT, *pStartTFromR, aStartTFromBR,
                aEndBFromTL, *pEndBFromL, *pEndBFromB, *pEndBFromR, aEndBFromTR );
    }
}

void Array::DrawArray( OutputDevice& rDev ) const
{
    if( mxImpl->mnWidth && mxImpl->mnHeight )
        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
#undef CELL
diff --git a/svx/source/dialog/frmsel.cxx b/svx/source/dialog/frmsel.cxx
index aaf9354..9356785 100644
--- a/svx/source/dialog/frmsel.cxx
+++ b/svx/source/dialog/frmsel.cxx
@@ -380,7 +380,6 @@ void FrameSelectorImpl::InitBorderGeometry()

    // Frame helper array
    maArray.Initialize( mbVer ? 2 : 1, mbHor ? 2 : 1 );
    maArray.SetUseDiagDoubleClipping( true );

    maArray.SetXOffset( mnLine1 );
    maArray.SetAllColWidths( (mbVer ? mnLine2 : mnLine3) - mnLine1 );
@@ -671,33 +670,25 @@ void FrameSelectorImpl::DrawAllFrameBorders()
    // Let the helper array draw itself
    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));
    // 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
    if (pProcessor2D)
    {
        // original paint
        maArray.DrawArray(*mpVirDev.get());
        maArray.DrawArray(*pProcessor2D.get());
        pProcessor2D.reset();
    }
}

diff --git a/sw/Library_swui.mk b/sw/Library_swui.mk
index a614daf..e33d164 100644
--- a/sw/Library_swui.mk
+++ b/sw/Library_swui.mk
@@ -71,6 +71,7 @@ $(eval $(call gb_Library_use_libraries,swui,\
    ucbhelper \
    utl \
    vcl \
    drawinglayer \
))

$(eval $(call gb_Library_add_exception_objects,swui,\
diff --git a/sw/source/core/layout/paintfrm.cxx b/sw/source/core/layout/paintfrm.cxx
index d136f6f..cbb9ed9 100644
--- a/sw/source/core/layout/paintfrm.cxx
+++ b/sw/source/core/layout/paintfrm.cxx
@@ -2746,11 +2746,16 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons

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

                svx::frame::CreateBorderPrimitives(
                    aSequence,
                    aPaintStart,
                    aPaintEnd,
                    aOrigin,
                    aX,
                    aY,
                    aStyles[ 0 ],   // current style
                    aStyles[ 1 ],   // aLFromT
                    aStyles[ 2 ],   // aLFromL
@@ -2763,11 +2768,16 @@ void SwTabFramePainter::PaintLines(OutputDevice& rDev, const SwRect& rRect) cons
            }
            else
            {
                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);

                svx::frame::CreateBorderPrimitives(
                    aSequence,
                    aPaintEnd,
                    aPaintStart,
                    aOrigin,
                    aX,
                    aY,
                    aStyles[ 0 ],   // current style
                    aStyles[ 4 ],   // aBFromL
                    aStyles[ 5 ],   // aBFromB
diff --git a/sw/source/ui/table/tautofmt.cxx b/sw/source/ui/table/tautofmt.cxx
index 0bb614d..6f4a5bf 100644
--- a/sw/source/ui/table/tautofmt.cxx
+++ b/sw/source/ui/table/tautofmt.cxx
@@ -24,7 +24,6 @@
#include <vcl/svapp.hxx>
#include <vcl/settings.hxx>
#include <vcl/builderfactory.hxx>

#include <svl/zforlist.hxx>
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#include <com/sun/star/i18n/BreakIterator.hpp>
@@ -32,6 +31,8 @@
#include <svtools/scriptedtext.hxx>
#include <svtools/accessibilityoptions.hxx>
#include <svx/framelinkarray.hxx>
#include <drawinglayer/processor2d/processor2dtools.hxx>

#include "app.hrc"
#include "strings.hrc"
#include "swmodule.hxx"
@@ -819,14 +820,25 @@ void AutoFormatPreview::PaintCells(vcl::RenderContext& rRenderContext)

    // 3) border
    if (aCurData.IsFrame())
        maArray.DrawArray(rRenderContext);
    {
        const drawinglayer::geometry::ViewInformation2D aNewViewInformation2D;
        std::unique_ptr<drawinglayer::processor2d::BaseProcessor2D> pProcessor2D(
            drawinglayer::processor2d::createPixelProcessor2DFromOutputDevice(
                rRenderContext,
                aNewViewInformation2D));

        if (pProcessor2D)
        {
            maArray.DrawArray(*pProcessor2D.get());
            pProcessor2D.reset();
        }
    }
}

void AutoFormatPreview::Init()
{
    SetBorderStyle( GetBorderStyle() | WindowBorderStyle::MONO );
    maArray.Initialize( 5, 5 );
    maArray.SetUseDiagDoubleClipping( false );
    nLabelColWidth = 0;
    nDataColWidth1 = 0;
    nDataColWidth2 = 0;