[Libreoffice-commits] core.git: Branch 'feature/borderline3' - basegfx/source include/basegfx include/svx svx/source

Armin Le Grand Armin.Le.Grand at cib.de
Wed Aug 30 18:45:50 UTC 2017


 basegfx/source/matrix/b2dhommatrixtools.cxx  |   14 
 include/basegfx/matrix/b2dhommatrixtools.hxx |    9 
 include/svx/framelink.hxx                    |   88 +++--
 include/svx/framelinkarray.hxx               |    3 
 svx/source/dialog/framelink.cxx              |  153 ++++------
 svx/source/dialog/framelinkarray.cxx         |  411 +++++++++++++--------------
 6 files changed, 364 insertions(+), 314 deletions(-)

New commits:
commit 211cc10b1b61526069bc3bf86a0ffc64645ad1f0
Author: Armin Le Grand <Armin.Le.Grand at cib.de>
Date:   Wed Aug 30 20:40:32 2017 +0200

    borderline: Preparing further to use CellCoordinateSystem
    
    Multiple cleanups, made svx::frame::Style a std::shared_ptr class,
    preparing basing all border stuff on transformations, so it will
    need a CellCoordinateSystem. Added stuff to get this Coordinate
    System from the svx::frame::Cell using the Frame and knowledge
    about ownerships
    
    Change-Id: Ic2cb59cc92e648ac2fef72f22f8913479769d3e2

diff --git a/basegfx/source/matrix/b2dhommatrixtools.cxx b/basegfx/source/matrix/b2dhommatrixtools.cxx
index 645d4c7e261a..89ab91424706 100644
--- a/basegfx/source/matrix/b2dhommatrixtools.cxx
+++ b/basegfx/source/matrix/b2dhommatrixtools.cxx
@@ -398,6 +398,20 @@ namespace basegfx
             return aRetval;
         }
 
+        B2DHomMatrix createCoordinateSystemTransform(
+            const B2DPoint& rOrigin,
+            const B2DVector& rX,
+            const B2DVector& rY)
+        {
+            return basegfx::B2DHomMatrix(
+                rX.getX(), rY.getX(), rOrigin.getX(),
+                rX.getY(), rY.getY(), rOrigin.getY());
+        }
+
+        B2DTuple getColumn(const B2DHomMatrix& rMatrix, sal_uInt16 nCol)
+        {
+            return B2DTuple(rMatrix.get(0, nCol), rMatrix.get(1, nCol));
+        }
     } // end of namespace tools
 } // end of namespace basegfx
 
diff --git a/include/basegfx/matrix/b2dhommatrixtools.hxx b/include/basegfx/matrix/b2dhommatrixtools.hxx
index 5dcd1b47936d..aa3c047a20c5 100644
--- a/include/basegfx/matrix/b2dhommatrixtools.hxx
+++ b/include/basegfx/matrix/b2dhommatrixtools.hxx
@@ -131,6 +131,15 @@ namespace basegfx
             const B2DRange& rSourceRange,
             const B2DRange& rTargetRange);
 
+        /// create based on given CoordinateSystem which is defined by origin and x/yaxis
+        BASEGFX_DLLPUBLIC B2DHomMatrix createCoordinateSystemTransform(
+            const B2DPoint& rOrigin,
+            const B2DVector& rX,
+            const B2DVector& rY);
+
+        /// get column vector from B2dHomMatrix, e.g. to extract coordinate system origin and x/yaxis
+        BASEGFX_DLLPUBLIC B2DTuple getColumn(const B2DHomMatrix& rMatrix, sal_uInt16 nCol);
+
     } // end of namespace tools
 } // end of namespace basegfx
 
diff --git a/include/svx/framelink.hxx b/include/svx/framelink.hxx
index 973c401f5aec..d0fb165eef79 100644
--- a/include/svx/framelink.hxx
+++ b/include/svx/framelink.hxx
@@ -107,6 +107,43 @@ enum class RefMode
  */
 class SAL_WARN_UNUSED SVX_DLLPUBLIC Style
 {
+private:
+    class implStyle
+    {
+    private:
+        friend class Style;
+
+        Color               maColorPrim;
+        Color               maColorSecn;
+        Color               maColorGap;
+        bool                mbUseGapColor;
+        RefMode             meRefMode;  /// Reference point handling for this frame border.
+        double              mfPrim;     /// Width of primary (single, left, or top) line.
+        double              mfDist;     /// Distance between primary and secondary line.
+        double              mfSecn;     /// Width of secondary (right or bottom) line.
+        double              mfPatternScale; /// Scale used for line pattern spacing.
+        SvxBorderLineStyle  mnType;
+        const Cell*         mpUsingCell;
+
+    public:
+        /** Constructs an invisible frame style. */
+        explicit implStyle() :
+            maColorPrim(),
+            maColorSecn(),
+            maColorGap(),
+            mbUseGapColor(false),
+            meRefMode(RefMode::Centered),
+            mfPrim(0.0),
+            mfDist(0.0),
+            mfSecn(0.0),
+            mfPatternScale(1.0),
+            mnType(SvxBorderLineStyle::SOLID),
+            mpUsingCell(nullptr)
+        {}
+    };
+
+    std::shared_ptr< implStyle >        maImplStyle;
+
 public:
     /** Constructs an invisible frame style. */
     explicit Style();
@@ -118,20 +155,20 @@ public:
     /** Constructs a frame style from the passed SvxBorderLine struct. Clears the style, if pBorder is 0. */
     explicit Style( const editeng::SvxBorderLine* pBorder, double fScale = 1.0 );
 
-    RefMode      GetRefMode() const { return meRefMode; }
-    const Color& GetColorPrim() const { return maColorPrim; }
-    const Color& GetColorSecn() const { return maColorSecn; }
-    const Color& GetColorGap() const { return maColorGap; }
-    bool         UseGapColor() const { return mbUseGapColor; }
-    double       Prim() const { return mfPrim; }
-    double       Dist() const { return mfDist; }
-    double       Secn() const { return mfSecn; }
-    double PatternScale() const { return mfPatternScale;}
-    void SetPatternScale( double fScale );
-    SvxBorderLineStyle Type() const { return mnType; }
+    RefMode      GetRefMode() const { return maImplStyle->meRefMode; }
+    const Color& GetColorPrim() const { return maImplStyle->maColorPrim; }
+    const Color& GetColorSecn() const { return maImplStyle->maColorSecn; }
+    const Color& GetColorGap() const { return maImplStyle->maColorGap; }
+    bool         UseGapColor() const { return maImplStyle->mbUseGapColor; }
+    double       Prim() const { return maImplStyle->mfPrim; }
+    double       Dist() const { return maImplStyle->mfDist; }
+    double       Secn() const { return maImplStyle->mfSecn; }
+    double PatternScale() const { return maImplStyle->mfPatternScale;}
+    void SetPatternScale( double fScale ) { maImplStyle->mfPatternScale = fScale; }
+    SvxBorderLineStyle Type() const { return maImplStyle->mnType; }
 
     /** Returns the total width of this frame style. */
-    double       GetWidth() const { return mfPrim + mfDist + mfSecn; }
+    double       GetWidth() const;
 
     /** Sets the frame style to invisible state. */
     void                Clear();
@@ -146,37 +183,24 @@ public:
     void                Set( const editeng::SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth = SAL_MAX_UINT16 );
 
     /** Sets a new reference point handling mode, does not modify other settings. */
-    void         SetRefMode( RefMode eRefMode ) { meRefMode = eRefMode; }
+    void         SetRefMode( RefMode eRefMode ) { maImplStyle->meRefMode = eRefMode; }
     /** Sets a new color, does not modify other settings. */
-    void         SetColorPrim( const Color& rColor ) { maColorPrim = rColor; }
-    void         SetColorSecn( const Color& rColor ) { maColorSecn = rColor; }
+    void         SetColorPrim( const Color& rColor ) { maImplStyle->maColorPrim = rColor; }
+    void         SetColorSecn( const Color& rColor ) { maImplStyle->maColorSecn = rColor; }
     /** Sets whether to use dotted style for single hair lines. */
-    void         SetType( SvxBorderLineStyle nType ) { mnType = nType; }
+    void         SetType( SvxBorderLineStyle nType ) { maImplStyle->mnType = nType; }
 
     /** Mirrors this style (exchanges primary and secondary), if it is a double frame style. */
     Style&              MirrorSelf();
 
     /** return the Cell using this style (if set) */
-    const Cell* GetUsingCell() const { return mpUsingCell; }
+    const Cell* GetUsingCell() const;
 
 private:
-    Color               maColorPrim;
-    Color               maColorSecn;
-    Color               maColorGap;
-    bool                mbUseGapColor;
-    RefMode             meRefMode;  /// Reference point handling for this frame border.
-    double              mfPrim;     /// Width of primary (single, left, or top) line.
-    double              mfDist;     /// Distance between primary and secondary line.
-    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;
+    friend class Cell;
+    void SetUsingCell(const Cell* pCell);
 };
 
 bool operator==( const Style& rL, const Style& rR );
diff --git a/include/svx/framelinkarray.hxx b/include/svx/framelinkarray.hxx
index 4801db277147..78b95c8d0ab0 100644
--- a/include/svx/framelinkarray.hxx
+++ b/include/svx/framelinkarray.hxx
@@ -292,6 +292,7 @@ public:
     /** Returns the output range of the cell (nCol,nRow).
         Returns total output range of merged ranges. */
     basegfx::B2DRange GetCellRange( size_t nCol, size_t nRow ) const;
+    basegfx::B2DRange GetCellRange( size_t nCellIndex ) const;
 
     // mirroring --------------------------------------------------------------
 
@@ -311,6 +312,8 @@ public:
     /** Draws the part of the array, that is inside the clipping range. */
     void                DrawArray(drawinglayer::processor2d::BaseProcessor2D& rProcessor) const;
 
+    // fill the Cell::maCellIndex entries to allow referencing back from Cell to Array Col/Row coordinates
+    void AddCellIndices() const;
 
 private:
     std::unique_ptr<ArrayImpl>        mxImpl;
diff --git a/svx/source/dialog/framelink.cxx b/svx/source/dialog/framelink.cxx
index cdfc9a202145..4f333828f3d6 100644
--- a/svx/source/dialog/framelink.cxx
+++ b/svx/source/dialog/framelink.cxx
@@ -41,64 +41,36 @@ using namespace editeng;
 namespace svx {
 namespace frame {
 
-
-namespace {
-
-/** Converts a width in twips to a width in another map unit (specified by fScale). */
-double lclScaleValue( double nValue, double fScale, sal_uInt16 nMaxWidth )
-{
-    return std::min<double>(nValue * fScale, nMaxWidth);
-}
-
-} // namespace
-
-
 // Classes
-
-
-#define SCALEVALUE( value ) lclScaleValue( value, fScale, nMaxWidth )
-
-Style::Style() :
-    meRefMode(RefMode::Centered),
-    mfPatternScale(1.0),
-    mnType(SvxBorderLineStyle::SOLID),
-    mpUsingCell(nullptr)
+Style::Style() : maImplStyle(new implStyle())
 {
     Clear();
 }
 
-Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType ) :
-    meRefMode(RefMode::Centered),
-    mfPatternScale(1.0),
-    mnType(nType),
-    mpUsingCell(nullptr)
+Style::Style( double nP, double nD, double nS, SvxBorderLineStyle nType ) : maImplStyle(new implStyle())
 {
+    maImplStyle->mnType = nType;
     Clear();
     Set( nP, nD, nS );
 }
 
-Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor,
-              double nP, double nD, double nS, SvxBorderLineStyle nType ) :
-    meRefMode(RefMode::Centered),
-    mfPatternScale(1.0),
-    mnType(nType),
-    mpUsingCell(nullptr)
+Style::Style( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS, SvxBorderLineStyle nType ) : maImplStyle(new implStyle())
 {
+    maImplStyle->mnType = nType;
     Set( rColorPrim, rColorSecn, rColorGap, bUseGapColor, nP, nD, nS );
 }
 
-Style::Style( const editeng::SvxBorderLine* pBorder, double fScale ) :
-    meRefMode(RefMode::Centered),
-    mfPatternScale(fScale),
-    mpUsingCell(nullptr)
+Style::Style( const editeng::SvxBorderLine* pBorder, double fScale ) : maImplStyle(new implStyle())
 {
+    maImplStyle->mfPatternScale = fScale;
     Set( pBorder, fScale );
 }
 
-
-void Style::SetPatternScale( double fScale )
+double Style::GetWidth() const
 {
-    mfPatternScale = fScale;
+    implStyle* pTarget = maImplStyle.get();
+
+    return pTarget->mfPrim + pTarget->mfDist + pTarget->mfSecn;
 }
 
 void Style::Clear()
@@ -115,66 +87,78 @@ void Style::Set( double nP, double nD, double nS )
         >0  0   >0      nP      0       0
         >0  >0  >0      nP      nD      nS
      */
-    mfPrim = rtl::math::round(nP ? nP : nS, 2);
-    mfDist = rtl::math::round((nP && nS) ? nD : 0, 2);
-    mfSecn = rtl::math::round((nP && nD) ? nS : 0, 2);
+    implStyle* pTarget = maImplStyle.get();
+    pTarget->mfPrim = rtl::math::round(nP ? nP : nS, 2);
+    pTarget->mfDist = rtl::math::round((nP && nS) ? nD : 0, 2);
+    pTarget->mfSecn = rtl::math::round((nP && nD) ? nS : 0, 2);
 }
 
 void Style::Set( const Color& rColorPrim, const Color& rColorSecn, const Color& rColorGap, bool bUseGapColor, double nP, double nD, double nS )
 {
-    maColorPrim = rColorPrim;
-    maColorSecn = rColorSecn;
-    maColorGap = rColorGap;
-    mbUseGapColor = bUseGapColor;
+    implStyle* pTarget = maImplStyle.get();
+    pTarget->maColorPrim = rColorPrim;
+    pTarget->maColorSecn = rColorSecn;
+    pTarget->maColorGap = rColorGap;
+    pTarget->mbUseGapColor = bUseGapColor;
     Set( nP, nD, nS );
 }
 
 void Style::Set( const SvxBorderLine& rBorder, double fScale, sal_uInt16 nMaxWidth )
 {
-    maColorPrim = rBorder.GetColorOut();
-    maColorSecn = rBorder.GetColorIn();
-    maColorGap = rBorder.GetColorGap();
-    mbUseGapColor = rBorder.HasGapColor();
+    implStyle* pTarget = maImplStyle.get();
+    pTarget->maColorPrim = rBorder.GetColorOut();
+    pTarget->maColorSecn = rBorder.GetColorIn();
+    pTarget->maColorGap = rBorder.GetColorGap();
+    pTarget->mbUseGapColor = rBorder.HasGapColor();
 
     sal_uInt16 nPrim = rBorder.GetOutWidth();
     sal_uInt16 nDist = rBorder.GetDistance();
     sal_uInt16 nSecn = rBorder.GetInWidth();
 
-    mnType = rBorder.GetBorderLineStyle();
+    pTarget->mnType = rBorder.GetBorderLineStyle();
     if( !nSecn )    // no or single frame border
     {
-        Set( SCALEVALUE( nPrim ), 0, 0 );
+        Set( std::min<double>(nPrim * fScale, nMaxWidth), 0, 0 );
     }
     else
     {
-        Set( SCALEVALUE( nPrim ), SCALEVALUE( nDist ), SCALEVALUE( nSecn ) );
+        Set(std::min<double>(nPrim * fScale, nMaxWidth), std::min<double>(nDist * fScale, nMaxWidth), std::min<double>(nSecn * fScale, nMaxWidth));
         // Enlarge the style if distance is too small due to rounding losses.
-        double nPixWidth = SCALEVALUE( nPrim + nDist + nSecn );
+        double nPixWidth = std::min<double>((nPrim + nDist + nSecn) * fScale, nMaxWidth);
+
         if( nPixWidth > GetWidth() )
-            mfDist = nPixWidth - mfPrim - mfSecn;
+        {
+            pTarget->mfDist = nPixWidth - pTarget->mfPrim - pTarget->mfSecn;
+        }
+
         // Shrink the style if it is too thick for the control.
         while( GetWidth() > nMaxWidth )
         {
             // First decrease space between lines.
-            if (mfDist)
-                --mfDist;
+            if (pTarget->mfDist)
+            {
+                --(pTarget->mfDist);
+                continue;
+            }
+
             // Still too thick? Decrease the line widths.
-            if( GetWidth() > nMaxWidth )
+            if (pTarget->mfPrim != 0.0 && rtl::math::approxEqual(pTarget->mfPrim, pTarget->mfSecn))
             {
-                if (mfPrim != 0.0 && rtl::math::approxEqual(mfPrim, mfSecn))
-                {
-                    // Both lines equal - decrease both to keep symmetry.
-                    --mfPrim;
-                    --mfSecn;
-                }
-                else
-                {
-                    // Decrease each line for itself
-                    if (mfPrim)
-                        --mfPrim;
-                    if ((GetWidth() > nMaxWidth) && mfSecn != 0.0)
-                        --mfSecn;
-                }
+                // Both lines equal - decrease both to keep symmetry.
+                --(pTarget->mfPrim);
+                --(pTarget->mfSecn);
+                continue;
+            }
+
+            // Decrease each line for itself
+            if (pTarget->mfPrim)
+            {
+                --(pTarget->mfPrim);
+            }
+
+            if ((GetWidth() > nMaxWidth) && pTarget->mfSecn != 0.0)
+            {
+                --(pTarget->mfSecn);
             }
         }
     }
@@ -183,23 +167,36 @@ void Style::Set( const SvxBorderLine& rBorder, double fScale, sal_uInt16 nMaxWid
 void Style::Set( const SvxBorderLine* pBorder, double fScale, sal_uInt16 nMaxWidth )
 {
     if( pBorder )
+    {
         Set( *pBorder, fScale, nMaxWidth );
+    }
     else
     {
         Clear();
-        mnType = SvxBorderLineStyle::SOLID;
+        maImplStyle->mnType = SvxBorderLineStyle::SOLID;
     }
 }
 
 Style& Style::MirrorSelf()
 {
-    if (mfSecn)
-        std::swap( mfPrim, mfSecn );
-    if( meRefMode != RefMode::Centered )
-        meRefMode = (meRefMode == RefMode::Begin) ? RefMode::End : RefMode::Begin;
+    implStyle* pTarget = maImplStyle.get();
+
+    if (pTarget->mfSecn)
+    {
+        std::swap( pTarget->mfPrim, pTarget->mfSecn );
+    }
+
+    if( pTarget->meRefMode != RefMode::Centered )
+    {
+        pTarget->meRefMode = (pTarget->meRefMode == RefMode::Begin) ? RefMode::End : RefMode::Begin;
+    }
+
     return *this;
 }
 
+const Cell* Style::GetUsingCell() const { return maImplStyle->mpUsingCell; }
+void Style::SetUsingCell(const Cell* pCell) { maImplStyle->mpUsingCell = pCell; }
+
 bool operator==( const Style& rL, const Style& rR )
 {
     return (rL.Prim() == rR.Prim()) && (rL.Dist() == rR.Dist()) && (rL.Secn() == rR.Secn()) &&
@@ -228,8 +225,6 @@ bool operator<( const Style& rL, const Style& rR )
     return false;
 }
 
-#undef SCALEVALUE
-
 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 )
diff --git a/svx/source/dialog/framelinkarray.cxx b/svx/source/dialog/framelinkarray.cxx
index ef6c410a7220..70a7175e7d96 100644
--- a/svx/source/dialog/framelinkarray.cxx
+++ b/svx/source/dialog/framelinkarray.cxx
@@ -24,14 +24,11 @@
 #include <algorithm>
 #include <vcl/outdev.hxx>
 #include <drawinglayer/primitive2d/borderlineprimitive2d.hxx>
+#include <basegfx/matrix/b2dhommatrixtools.hxx>
 
 namespace svx {
 namespace frame {
 
-/// 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:
@@ -48,8 +45,10 @@ public:
     long                mnAddTop;
     long                mnAddBottom;
 
-    SvxRotateMode       meRotMode;
-    double              mfOrientation;
+    SvxRotateMode           meRotMode;
+    double                  mfOrientation;
+    basegfx::B2DHomMatrix   maCoordinateSystem;
+    size_t                  maCellIndex;
 
     bool                mbMergeOrig;
     bool                mbOverlapX;
@@ -58,12 +57,12 @@ public:
 public:
     explicit            Cell();
 
-    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); }
+    void SetStyleLeft(const Style& rStyle) { maLeft = rStyle; maLeft.SetUsingCell(this); }
+    void SetStyleRight(const Style& rStyle) { maRight = rStyle; maRight.SetUsingCell(this); }
+    void SetStyleTop(const Style& rStyle) { maTop = rStyle; maTop.SetUsingCell(this); }
+    void SetStyleBottom(const Style& rStyle) { maBottom = rStyle; maBottom.SetUsingCell(this); }
+    void SetStyleTLBR(const Style& rStyle) { maTLBR = rStyle; maTLBR.SetUsingCell(this); }
+    void SetStyleBLTR(const Style& rStyle) { maBLTR = rStyle; maBLTR.SetUsingCell(this); }
 
     const Style& GetStyleLeft() const { return maLeft; }
     const Style& GetStyleRight() const { return maRight; }
@@ -76,11 +75,65 @@ public:
     bool                IsRotated() const { return mfOrientation != 0.0; }
 
     void                MirrorSelfX();
+
+    basegfx::B2DHomMatrix CreateCoordinateSystem(const Array& rArray) const;
 };
 
 typedef std::vector< long >     LongVec;
 typedef std::vector< Cell >     CellVec;
 
+basegfx::B2DHomMatrix Cell::CreateCoordinateSystem(const Array& rArray) const
+{
+    if(!maCoordinateSystem.isIdentity())
+    {
+        return maCoordinateSystem;
+    }
+
+    if(-1 == maCellIndex)
+    {
+        rArray.AddCellIndices();
+    }
+
+    if(-1 != maCellIndex)
+    {
+        const basegfx::B2DRange aRange(rArray.GetCellRange(maCellIndex));
+        basegfx::B2DPoint aOrigin(aRange.getMinimum());
+        basegfx::B2DVector aX(aRange.getWidth(), 0.0);
+        basegfx::B2DVector aY(0.0, aRange.getHeight());
+
+        if (IsRotated() && SvxRotateMode::SVX_ROTATE_MODE_STANDARD != meRotMode)
+        {
+            // when rotated, adapt values. Get Skew (cos/sin == 1/tan)
+            const double fSkew(aY.getY() * (cos(mfOrientation) / sin(mfOrientation)));
+
+            switch (meRotMode)
+            {
+            case SvxRotateMode::SVX_ROTATE_MODE_TOP:
+                // shear Y-Axis
+                aY.setX(-fSkew);
+                break;
+            case SvxRotateMode::SVX_ROTATE_MODE_CENTER:
+                // shear origin half, Y full
+                aOrigin.setX(aOrigin.getX() + (fSkew * 0.5));
+                aY.setX(-fSkew);
+                break;
+            case SvxRotateMode::SVX_ROTATE_MODE_BOTTOM:
+                // shear origin full, Y full
+                aOrigin.setX(aOrigin.getX() + fSkew);
+                aY.setX(-fSkew);
+                break;
+            default: // SvxRotateMode::SVX_ROTATE_MODE_STANDARD, already excluded above
+                break;
+            }
+        }
+
+        // use column vectors as coordinate axes, homogen column for translation
+        const_cast<Cell*>(this)->maCoordinateSystem = basegfx::tools::createCoordinateSystemTransform(aOrigin, aX, aY);
+    }
+
+    return maCoordinateSystem;
+}
+
 Cell::Cell() :
     mnAddLeft( 0 ),
     mnAddRight( 0 ),
@@ -88,6 +141,8 @@ Cell::Cell() :
     mnAddBottom( 0 ),
     meRotMode(SvxRotateMode::SVX_ROTATE_MODE_STANDARD ),
     mfOrientation( 0.0 ),
+    maCoordinateSystem(),
+    maCellIndex(static_cast<size_t>(-1)),
     mbMergeOrig( false ),
     mbOverlapX( false ),
     mbOverlapY( false )
@@ -101,6 +156,8 @@ void Cell::MirrorSelfX()
     maLeft.MirrorSelf();
     maRight.MirrorSelf();
     mfOrientation = -mfOrientation;
+    maCoordinateSystem.identity();
+    maCellIndex = static_cast<size_t>(-1);
 }
 
 
@@ -808,6 +865,11 @@ long Array::GetHeight() const
     return GetRowPosition( mxImpl->mnHeight ) - GetRowPosition( 0 );
 }
 
+basegfx::B2DRange Array::GetCellRange( size_t nCellIndex ) const
+{
+    return GetCellRange(nCellIndex % GetColCount(), nCellIndex / GetColCount());
+}
+
 basegfx::B2DRange Array::GetCellRange( size_t nCol, size_t nRow ) const
 {
     size_t nFirstCol = mxImpl->GetMergedFirstCol( nCol, nRow );
@@ -866,46 +928,6 @@ 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, already 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
@@ -942,17 +964,13 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                     if (rTLBR.GetWidth() || rBLTR.GetWidth())
                     {
                         drawinglayer::primitive2d::Primitive2DContainer aSequence;
-                        basegfx::B2DPoint aOrigin;
-                        basegfx::B2DVector aX;
-                        basegfx::B2DVector aY;
-
-                        CreateCoordinateSystemForCell(aRange, rCell, aOrigin, aX, aY);
+                        basegfx::B2DHomMatrix aCoordinateSystem(rCell.CreateCoordinateSystem(*this));
 
                         CreateDiagFrameBorderPrimitives(
                             aSequence,
-                            aOrigin,
-                            aX,
-                            aY,
+                            basegfx::tools::getColumn(aCoordinateSystem, 2),
+                            basegfx::tools::getColumn(aCoordinateSystem, 0),
+                            basegfx::tools::getColumn(aCoordinateSystem, 1),
                             rTLBR,
                             rBLTR,
                             GetCellStyleLeft(_nFirstCol, _nFirstRow),
@@ -1016,54 +1034,40 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                 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())
+                    if(pCell)
                     {
-                        // 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
+                        basegfx::B2DHomMatrix aCoordinateSystem(pCell->CreateCoordinateSystem(*this));
                         const bool bUpper(&pCell->GetStyleTop() == pStart);
-                        const basegfx::B2DRange aRange(GetCellRange(nCol - 1, bUpper ? nRow : nRow - 1));
 
-                        // adapt to cell coordinate system, including shear
-                        CreateCoordinateSystemForCell(aRange, *pCell, aOrigin, aX, aY);
-
-                        if (!bUpper)
+                        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
+                            aCoordinateSystem.set(0, 2, aCoordinateSystem.get(0, 2) + aCoordinateSystem.get(0, 1));
+                            aCoordinateSystem.set(1, 2, aCoordinateSystem.get(1, 2) + aCoordinateSystem.get(1, 1));
                         }
-
-                        // borderline coordinate system uses normalized 2nd axis
-                        aY.normalize();
+                        drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                        CreateBorderPrimitives(
+                            aSequence,
+                            basegfx::tools::getColumn(aCoordinateSystem, 2),
+                            basegfx::tools::getColumn(aCoordinateSystem, 0),
+                            basegfx::B2DVector(basegfx::tools::getColumn(aCoordinateSystem, 1)).normalize(),
+                            *pStart,
+                            aStartLFromTR,
+                            *pStartLFromT,
+                            *pStartLFromL,
+                            *pStartLFromB,
+                            aStartLFromBR,
+                            aEndRFromTL,
+                            *pEndRFromT,
+                            *pEndRFromR,
+                            *pEndRFromB,
+                            aEndRFromBL,
+                            pForceColor);
+                        rProcessor.process(aSequence);
                     }
-
-                    drawinglayer::primitive2d::Primitive2DContainer aSequence;
-                    CreateBorderPrimitives(
-                        aSequence,
-                        aOrigin,
-                        aX,
-                        aY,
-                        *pStart,
-                        aStartLFromTR,
-                        *pStartLFromT,
-                        *pStartLFromL,
-                        *pStartLFromB,
-                        aStartLFromBR,
-                        aEndRFromTL,
-                        *pEndRFromT,
-                        *pEndRFromR,
-                        *pEndRFromB,
-                        aEndRFromBL,
-                        pForceColor);
-                    rProcessor.process(aSequence);
                 }
 
                 // re-init "*Start***" variables
@@ -1090,45 +1094,41 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
         {
             // 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())
+            if(pCell)
             {
+                basegfx::B2DHomMatrix aCoordinateSystem(pCell->CreateCoordinateSystem(*this));
                 const bool bUpper(&pCell->GetStyleTop() == pStart);
-                const basegfx::B2DRange aRange(GetCellRange(nCol - 1, bUpper ? nRow : nRow - 1));
-
-                CreateCoordinateSystemForCell(aRange, *pCell, aOrigin, aX, aY);
 
-                if (!bUpper)
+                if(!bUpper)
                 {
-                    aOrigin += aY;
+                    // for the lower edge we need to translate to get to the
+                    // borderline coordinate system
+                    aCoordinateSystem.set(0, 2, aCoordinateSystem.get(0, 2) + aCoordinateSystem.get(0, 1));
+                    aCoordinateSystem.set(1, 2, aCoordinateSystem.get(1, 2) + aCoordinateSystem.get(1, 1));
                 }
 
-                aY.normalize();
+                drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                CreateBorderPrimitives(
+                    aSequence,
+                    basegfx::tools::getColumn(aCoordinateSystem, 2),
+                    basegfx::tools::getColumn(aCoordinateSystem, 0),
+                    basegfx::B2DVector(basegfx::tools::getColumn(aCoordinateSystem, 1)).normalize(),
+                    *pStart,
+                    aStartLFromTR,
+                    *pStartLFromT,
+                    *pStartLFromL,
+                    *pStartLFromB,
+                    aStartLFromBR,
+                    aEndRFromTL,
+                    *pEndRFromT,
+                    *pEndRFromR,
+                    *pEndRFromB,
+                    aEndRFromBL,
+                    pForceColor);
+                rProcessor.process(aSequence);
             }
-
-            drawinglayer::primitive2d::Primitive2DContainer aSequence;
-            CreateBorderPrimitives(
-                aSequence,
-                aOrigin,
-                aX,
-                aY,
-                *pStart,
-                aStartLFromTR,
-                *pStartLFromT,
-                *pStartLFromL,
-                *pStartLFromB,
-                aStartLFromBR,
-                aEndRFromTL,
-                *pEndRFromT,
-                *pEndRFromR,
-                *pEndRFromB,
-                aEndRFromBL,
-                pForceColor);
-            rProcessor.process(aSequence);
         }
     }
 
@@ -1177,59 +1177,57 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
                 {
                     // 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())
+                    if(pCell)
                     {
+                         basegfx::B2DHomMatrix aCoordinateSystem(pCell->CreateCoordinateSystem(*this));
                         const bool bLeft(&pCell->GetStyleLeft() == pStart);
-                        const  basegfx::B2DRange aRange(GetCellRange(bLeft ? nCol : nCol - 1, nRow - 1));
 
-                        CreateCoordinateSystemForCell(aRange, *pCell, aOrigin, aX, aY);
-
-                        if (!bLeft)
+                        if(!bLeft)
                         {
-                            aOrigin += aX;
+                            // for the Right edge we need to translate to get to the
+                            // borderline coordinate system
+                            aCoordinateSystem.set(0, 2, aCoordinateSystem.get(0, 2) + aCoordinateSystem.get(0, 0));
+                            aCoordinateSystem.set(1, 2, aCoordinateSystem.get(1, 2) + aCoordinateSystem.get(1, 0));
                         }
 
                         // 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 test here, checked in debug mode)
-                        std::swap(aX, aY);
-                        aY.normalize();
-                        aY = -aY;
-                    }
+                        const basegfx::B2DTuple aX(basegfx::tools::getColumn(aCoordinateSystem, 0));
+                        const basegfx::B2DTuple aY(basegfx::tools::getColumn(aCoordinateSystem, 1));
+                        aCoordinateSystem = basegfx::tools::createCoordinateSystemTransform(basegfx::tools::getColumn(aCoordinateSystem, 2), aY, -aX);
 
-                    drawinglayer::primitive2d::Primitive2DContainer aSequence;
-                    CreateBorderPrimitives(
-                        // This replaces DrawVerFrameBorder which went from top to bottom. To be able to use
-                        // the same method as for horizontal (CreateBorderPrimitives), the given borders
-                        // have to be rearranged. Best is to look at the explanations of parameters in
-                        // framelink.hxx and the former calls to DrawVerFrameBorder and it's parameters.
-                        // In principle, the order of the five TFrom and BFrom has to be
-                        // inverted to get the same orientation. Before, EndPos and StartPos were changed
-                        // which avoids the reordering, but also leads to inverted line patters for vertical
-                        // lines.
-                        aSequence,
-                        aOrigin,
-                        aX,
-                        aY,
-                        *pStart,
-                        aStartTFromBR,
-                        *pStartTFromR,
-                        *pStartTFromT,
-                        *pStartTFromL,
-                        aStartTFromBL,
-                        aEndBFromTR,
-                        *pEndBFromR,
-                        *pEndBFromB,
-                        *pEndBFromL,
-                        aEndBFromTL,
-                        pForceColor);
-                    rProcessor.process(aSequence);
+                        drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                        CreateBorderPrimitives(
+                            // This replaces DrawVerFrameBorder which went from top to bottom. To be able to use
+                            // the same method as for horizontal (CreateBorderPrimitives), the given borders
+                            // have to be rearranged. Best is to look at the explanations of parameters in
+                            // framelink.hxx and the former calls to DrawVerFrameBorder and it's parameters.
+                            // In principle, the order of the five TFrom and BFrom has to be
+                            // inverted to get the same orientation. Before, EndPos and StartPos were changed
+                            // which avoids the reordering, but also leads to inverted line patters for vertical
+                            // lines.
+                            aSequence,
+                            basegfx::tools::getColumn(aCoordinateSystem, 2),
+                            basegfx::tools::getColumn(aCoordinateSystem, 0),
+                            basegfx::B2DVector(basegfx::tools::getColumn(aCoordinateSystem, 1)).normalize(),
+                            *pStart,
+                            aStartTFromBR,
+                            *pStartTFromR,
+                            *pStartTFromT,
+                            *pStartTFromL,
+                            aStartTFromBL,
+                            aEndBFromTR,
+                            *pEndBFromR,
+                            *pEndBFromB,
+                            *pEndBFromL,
+                            aEndBFromTL,
+                            pForceColor);
+                        rProcessor.process(aSequence);
+                    }
                 }
 
                 // re-init "*Start***" variables
@@ -1256,51 +1254,50 @@ void Array::DrawRange( drawinglayer::processor2d::BaseProcessor2D& rProcessor,
         {
             // 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())
+            if(pCell)
             {
+                basegfx::B2DHomMatrix aCoordinateSystem(pCell->CreateCoordinateSystem(*this));
                 const bool bLeft(&pCell->GetStyleLeft() == pStart);
-                const basegfx::B2DRange aRange(GetCellRange(bLeft ? nCol : nCol - 1, nRow - 1));
 
-                CreateCoordinateSystemForCell(aRange, *pCell, aOrigin, aX, aY);
-
-                if (!bLeft)
+                if(!bLeft)
                 {
-                    aOrigin += aX;
+                    // for the Right edge we need to translate to get to the
+                    // borderline coordinate system
+                    aCoordinateSystem.set(0, 2, aCoordinateSystem.get(0, 2) + aCoordinateSystem.get(0, 0));
+                    aCoordinateSystem.set(1, 2, aCoordinateSystem.get(1, 2) + aCoordinateSystem.get(1, 0));
                 }
 
                 // 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;
+                // and mirror aX to keep the same orientation (should be (-1.0, 0.0) for
+                // horizontal lines anyways, this could be used as test here, checked in debug mode)
+                const basegfx::B2DTuple aX(basegfx::tools::getColumn(aCoordinateSystem, 0));
+                const basegfx::B2DTuple aY(basegfx::tools::getColumn(aCoordinateSystem, 1));
+                aCoordinateSystem = basegfx::tools::createCoordinateSystemTransform(basegfx::tools::getColumn(aCoordinateSystem, 2), aY, -aX);
+
+                drawinglayer::primitive2d::Primitive2DContainer aSequence;
+                CreateBorderPrimitives(
+                    // also reordered, see call to CreateBorderPrimitives above
+                    aSequence,
+                    basegfx::tools::getColumn(aCoordinateSystem, 2),
+                    basegfx::tools::getColumn(aCoordinateSystem, 0),
+                    basegfx::B2DVector(basegfx::tools::getColumn(aCoordinateSystem, 1)).normalize(),
+                    *pStart,
+                    aStartTFromBR,
+                    *pStartTFromR,
+                    *pStartTFromT,
+                    *pStartTFromL,
+                    aStartTFromBL,
+                    aEndBFromTR,
+                    *pEndBFromR,
+                    *pEndBFromB,
+                    *pEndBFromL,
+                    aEndBFromTL,
+                    pForceColor);
+                rProcessor.process(aSequence);
             }
-
-            drawinglayer::primitive2d::Primitive2DContainer aSequence;
-            CreateBorderPrimitives(
-                // also reordered, see call to CreateBorderPrimitives above
-                aSequence,
-                aOrigin,
-                aX,
-                aY,
-                *pStart,
-                aStartTFromBR,
-                *pStartTFromR,
-                *pStartTFromT,
-                *pStartTFromL,
-                aStartTFromBL,
-                aEndBFromTR,
-                *pEndBFromR,
-                *pEndBFromB,
-                *pEndBFromL,
-                aEndBFromTL,
-                pForceColor);
-            rProcessor.process(aSequence);
         }
     }
 }
@@ -1311,6 +1308,14 @@ void Array::DrawArray(drawinglayer::processor2d::BaseProcessor2D& rProcessor) co
         DrawRange(rProcessor, 0, 0, mxImpl->mnWidth - 1, mxImpl->mnHeight - 1, nullptr);
 }
 
+void Array::AddCellIndices() const
+{
+    for (size_t a(0); a < mxImpl->maCells.size(); a++)
+    {
+        const_cast<Array*>(this)->mxImpl->maCells[a].maCellIndex = a;
+    }
+}
+
 #undef ORIGCELL
 #undef CELLACC
 #undef CELL


More information about the Libreoffice-commits mailing list