basegfx/source/matrix/b2dhommatrix.cxx           |  211 +++++++++++------------
 basegfx/source/point/b2dpoint.cxx                |   15 -
 basegfx/source/point/b2ipoint.cxx                |   15 -
 basegfx/test/B2DHomMatrixTest.cxx                |   54 -----
 chart2/source/tools/CommonConverters.cxx         |   13 -
 drawinglayer/source/texture/texture.cxx          |   14 -
 drawinglayer/source/tools/primitive2dxmldump.cxx |    6 
 filter/source/msfilter/eschesdo.cxx              |    7 
 include/basegfx/matrix/b2dhommatrix.hxx          |   60 +++---
 oox/source/drawingml/shape.cxx                   |    6 
 oox/source/shape/WpsContext.cxx                  |    7 
 svx/source/unodraw/unoshape.cxx                  |   13 -
 sw/source/core/edit/edfcol.cxx                   |   13 -
 sw/source/core/unocore/unodraw.cxx               |   13 -
 xmloff/source/draw/shapeexport.cxx               |    7 
 xmloff/source/draw/ximpshap.cxx                  |    6 
 16 files changed, 181 insertions(+), 279 deletions(-)

New commits:
commit fdd06037e0cf902d71270c4bf7a867efc7c9c1f4
Author:     Noel Grandin <noelgran...@gmail.com>
AuthorDate: Wed May 17 20:13:03 2023 +0200
Commit:     Noel Grandin <noel.gran...@collabora.co.uk>
CommitDate: Thu May 18 21:18:06 2023 +0200

    improved B2DHomMatrix
    
    since we know that this is a matrix only used for 2D transforms,
    we know that the last row of the matrix is always { 0, 0, 1 }.
    
    Therefore, we don't need to store that information, and
    we can simplify some of the computations.
    
    Also remove operations like operator+ which are not legal for
    such a matrix.
    
    Change-Id: I482de9a45ebbedf79e3b6033575aab590e61c2d5
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/151909
    Tested-by: Jenkins
    Reviewed-by: Noel Grandin <noel.gran...@collabora.co.uk>

diff --git a/basegfx/source/matrix/b2dhommatrix.cxx 
b/basegfx/source/matrix/b2dhommatrix.cxx
index 4222c7a351c2..e4a9dda9e3c5 100644
--- a/basegfx/source/matrix/b2dhommatrix.cxx
+++ b/basegfx/source/matrix/b2dhommatrix.cxx
@@ -26,50 +26,56 @@
 
 namespace basegfx
 {
-
-    B2DHomMatrix::B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, 
double f_1x0, double f_1x1, double f_1x2)
-    {
-        maImpl.set(0, 0, f_0x0);
-        maImpl.set(0, 1, f_0x1);
-        maImpl.set(0, 2, f_0x2);
-        maImpl.set(1, 0, f_1x0);
-        maImpl.set(1, 1, f_1x1);
-        maImpl.set(1, 2, f_1x2);
-    }
-
-    void B2DHomMatrix::set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
-    {
-        maImpl.set(nRow, nColumn, fValue);
-    }
+    constexpr int RowSize = 3;
 
     void B2DHomMatrix::set3x2(double f_0x0, double f_0x1, double f_0x2, double 
f_1x0, double f_1x1, double f_1x2)
     {
-        maImpl.set(0, 0, f_0x0);
-        maImpl.set(0, 1, f_0x1);
-        maImpl.set(0, 2, f_0x2);
-        maImpl.set(1, 0, f_1x0);
-        maImpl.set(1, 1, f_1x1);
-        maImpl.set(1, 2, f_1x2);
-    }
-
-    bool B2DHomMatrix::isLastLineDefault() const
-    {
-        return maImpl.isLastLineDefault();
+        mfValues[0][0] = f_0x0;
+        mfValues[0][1] = f_0x1;
+        mfValues[0][2] = f_0x2;
+        mfValues[1][0] = f_1x0;
+        mfValues[1][1] = f_1x1;
+        mfValues[1][2] = f_1x2;
     }
 
     bool B2DHomMatrix::isIdentity() const
     {
-        return maImpl.isIdentity();
+        for(sal_uInt16 a(0); a < RowSize - 1; a++)
+        {
+            for(sal_uInt16 b(0); b < RowSize; b++)
+            {
+                const double fDefault(internal::implGetDefaultValue(a, b));
+                const double fValueAB(get(a, b));
+
+                if(!::basegfx::fTools::equal(fDefault, fValueAB))
+                {
+                    return false;
+                }
+            }
+        }
+
+        return true;
     }
 
     void B2DHomMatrix::identity()
     {
-        maImpl = Impl2DHomMatrix();
+        for(sal_uInt16 a(0); a < RowSize - 1; a++)
+        {
+            for(sal_uInt16 b(0); b < RowSize; b++)
+                mfValues[a][b] = internal::implGetDefaultValue(a, b);
+        }
     }
 
     bool B2DHomMatrix::isInvertible() const
     {
-        return maImpl.isInvertible();
+        double dst[6];
+        /* Compute adjoint: */
+        computeAdjoint(dst);
+        /* Compute determinant: */
+        double det = computeDeterminant(dst);
+        if (fTools::equalZero(det))
+            return false;
+        return true;
     }
 
     bool B2DHomMatrix::invert()
@@ -77,85 +83,43 @@ namespace basegfx
         if(isIdentity())
             return true;
 
-
-        double dst[9];
+        double dst[6];
 
         /* Compute adjoint: */
-
-        dst[0] = + get(1, 1) * get(2, 2) - get(1, 2) * get(2, 1);
-        dst[1] = - get(0, 1) * get(2, 2) + get(0, 2) * get(2, 1);
-        dst[2] = + get(0, 1) * get(1, 2) - get(0, 2) * get(1, 1);
-        dst[3] = - get(1, 0) * get(2, 2) + get(1, 2) * get(2, 0);
-        dst[4] = + get(0, 0) * get(2, 2) - get(0, 2) * get(2, 0);
-        dst[5] = - get(0, 0) * get(1, 2) + get(0, 2) * get(1, 0);
-        dst[6] = + get(1, 0) * get(2, 1) - get(1, 1) * get(2, 0);
-        dst[7] = - get(0, 0) * get(2, 1) + get(0, 1) * get(2, 0);
-        dst[8] = + get(0, 0) * get(1, 1) - get(0, 1) * get(1, 0);
+        computeAdjoint(dst);
 
         /* Compute determinant: */
-
-        double det = get(0, 0) * dst[0] + get(0, 1) * dst[3] + get(0, 2) * 
dst[6];
+        double det = computeDeterminant(dst);
         if (fTools::equalZero(det))
             return false;
 
         /* Multiply adjoint with reciprocal of determinant: */
-
         det = 1.0 / det;
-
-        maImpl.set(0, 0, dst[0] * det);
-        maImpl.set(0, 1, dst[1] * det);
-        maImpl.set(0, 2, dst[2] * det);
-        maImpl.set(1, 0, dst[3] * det);
-        maImpl.set(1, 1, dst[4] * det);
-        maImpl.set(1, 2, dst[5] * det);
-        maImpl.set(2, 0, dst[6] * det);
-        maImpl.set(2, 1, dst[7] * det);
-        maImpl.set(2, 2, dst[8] * det);
-
-        // The above algorithm is very slightly less accurate then the old 
one, so
-        // we need to round the last row to make sure that functions like 
decompose
-        // still do the same thing with existing data, otherwise testTdf109143
-        // in CppunitTest_vcl_pdfexport will fail.
-        if (fTools::equalZero(maImpl.get(2, 0)))
-            maImpl.set(2, 0, 0);
-        if (fTools::equalZero(maImpl.get(2, 1)))
-            maImpl.set(2, 1, 0);
-        if (fTools::equal(1.0, maImpl.get(2, 2)))
-            maImpl.set(2, 2, 1);
+        mfValues[0][0] = dst[0] * det;
+        mfValues[0][1] = dst[1] * det;
+        mfValues[0][2] = dst[2] * det;
+        mfValues[1][0] = dst[3] * det;
+        mfValues[1][1] = dst[4] * det;
+        mfValues[1][2] = dst[5] * det;
 
         return true;
     }
 
-    B2DHomMatrix& B2DHomMatrix::operator+=(const B2DHomMatrix& rMat)
+    /* Compute adjoint, optimised for the case where the last (not stored) row 
is { 0, 0, 1 } */
+    void B2DHomMatrix::computeAdjoint(double (&dst)[6]) const
     {
-        maImpl.doAddMatrix(rMat.maImpl);
-        return *this;
-    }
-
-    B2DHomMatrix& B2DHomMatrix::operator-=(const B2DHomMatrix& rMat)
-    {
-        maImpl.doSubMatrix(rMat.maImpl);
-        return *this;
+        dst[0] = + get(1, 1);
+        dst[1] = - get(0, 1);
+        dst[2] = + get(0, 1) * get(1, 2) - get(0, 2) * get(1, 1);
+        dst[3] = - get(1, 0);
+        dst[4] = + get(0, 0);
+        dst[5] = - get(0, 0) * get(1, 2) + get(0, 2) * get(1, 0);
     }
 
-    B2DHomMatrix& B2DHomMatrix::operator*=(double fValue)
+    /* Compute the determinant, given the adjoint matrix */
+    double B2DHomMatrix::computeDeterminant(double (&dst)[6]) const
     {
-        const double fOne(1.0);
-
-        if(!fTools::equal(fOne, fValue))
-            maImpl.doMulMatrix(fValue);
-
-        return *this;
-    }
-
-    B2DHomMatrix& B2DHomMatrix::operator/=(double fValue)
-    {
-        const double fOne(1.0);
-
-        if(!fTools::equal(fOne, fValue))
-            maImpl.doMulMatrix(1.0 / fValue);
-
-        return *this;
+        return mfValues[0][0] * dst[0] + mfValues[0][1] * dst[3];
     }
 
     B2DHomMatrix& B2DHomMatrix::operator*=(const B2DHomMatrix& rMat)
@@ -172,15 +136,50 @@ namespace basegfx
         else
         {
             // multiply
-            maImpl.doMulMatrix(rMat.maImpl);
+            doMulMatrix(rMat);
         }
 
         return *this;
     }
 
+    void B2DHomMatrix::doMulMatrix(const B2DHomMatrix& rMat)
+    {
+        // create a copy as source for the original values
+        const B2DHomMatrix aCopy(*this);
+
+        for(sal_uInt16 a(0); a < 2; ++a)
+        {
+            for(sal_uInt16 b(0); b < 3; ++b)
+            {
+                double fValue = 0.0;
+
+                for(sal_uInt16 c(0); c < 2; ++c)
+                    fValue += aCopy.mfValues[c][b] * rMat.mfValues[a][c];
+
+                mfValues[a][b] = fValue;
+            }
+            mfValues[a][2] += rMat.mfValues[a][2];
+        }
+    }
+
     bool B2DHomMatrix::operator==(const B2DHomMatrix& rMat) const
     {
-        return &rMat == this || maImpl.isEqual(rMat.maImpl);
+        if (&rMat == this)
+            return true;
+        for(sal_uInt16 a(0); a < 2; a++)
+        {
+            for(sal_uInt16 b(0); b < 3; b++)
+            {
+                const double fValueA(mfValues[a][b]);
+                const double fValueB(rMat.mfValues[a][b]);
+
+                if(!::basegfx::fTools::equal(fValueA, fValueB))
+                {
+                    return false;
+                }
+            }
+        }
+        return true;
     }
 
     bool B2DHomMatrix::operator!=(const B2DHomMatrix& rMat) const
@@ -197,26 +196,26 @@ namespace basegfx
         double fCos(1.0);
 
         utils::createSinCosOrthogonal(fSin, fCos, fRadiant);
-        Impl2DHomMatrix aRotMat;
+        B2DHomMatrix aRotMat;
 
         aRotMat.set(0, 0, fCos);
         aRotMat.set(1, 1, fCos);
         aRotMat.set(1, 0, fSin);
         aRotMat.set(0, 1, -fSin);
 
-        maImpl.doMulMatrix(aRotMat);
+        doMulMatrix(aRotMat);
     }
 
     void B2DHomMatrix::translate(double fX, double fY)
     {
         if(!fTools::equalZero(fX) || !fTools::equalZero(fY))
         {
-            Impl2DHomMatrix aTransMat;
+            B2DHomMatrix aTransMat;
 
             aTransMat.set(0, 2, fX);
             aTransMat.set(1, 2, fY);
 
-            maImpl.doMulMatrix(aTransMat);
+            doMulMatrix(aTransMat);
         }
     }
 
@@ -231,12 +230,12 @@ namespace basegfx
 
         if(!fTools::equal(fOne, fX) || !fTools::equal(fOne, fY))
         {
-            Impl2DHomMatrix aScaleMat;
+            B2DHomMatrix aScaleMat;
 
             aScaleMat.set(0, 0, fX);
             aScaleMat.set(1, 1, fY);
 
-            maImpl.doMulMatrix(aScaleMat);
+            doMulMatrix(aScaleMat);
         }
     }
 
@@ -250,11 +249,11 @@ namespace basegfx
         // #i76239# do not test against 1.0, but against 0.0. We are talking 
about a value not on the diagonal (!)
         if(!fTools::equalZero(fSx))
         {
-            Impl2DHomMatrix aShearXMat;
+            B2DHomMatrix aShearXMat;
 
             aShearXMat.set(0, 1, fSx);
 
-            maImpl.doMulMatrix(aShearXMat);
+            doMulMatrix(aShearXMat);
         }
     }
 
@@ -263,11 +262,11 @@ namespace basegfx
         // #i76239# do not test against 1.0, but against 0.0. We are talking 
about a value not on the diagonal (!)
         if(!fTools::equalZero(fSy))
         {
-            Impl2DHomMatrix aShearYMat;
+            B2DHomMatrix aShearYMat;
 
             aShearYMat.set(1, 0, fSy);
 
-            maImpl.doMulMatrix(aShearYMat);
+            doMulMatrix(aShearYMat);
         }
     }
 
@@ -280,12 +279,6 @@ namespace basegfx
     */
     bool B2DHomMatrix::decompose(B2DTuple& rScale, B2DTuple& rTranslate, 
double& rRotate, double& rShearX) const
     {
-        // when perspective is used, decompose is not made here
-        if(!maImpl.isLastLineDefault())
-        {
-            return false;
-        }
-
         // reset rotate and shear and copy translation values in every case
         rRotate = rShearX = 0.0;
         rTranslate.setX(get(0, 2));
diff --git a/basegfx/source/point/b2dpoint.cxx 
b/basegfx/source/point/b2dpoint.cxx
index 02e6711ac44c..1d7f75158526 100644
--- a/basegfx/source/point/b2dpoint.cxx
+++ b/basegfx/source/point/b2dpoint.cxx
@@ -34,21 +34,6 @@ namespace basegfx
             rMat.get(1, 1) * mfY +
             rMat.get(1, 2));
 
-        if(!rMat.isLastLineDefault())
-        {
-            const double fOne(1.0);
-            const double fTempM(
-                rMat.get(2, 0) * mfX +
-                rMat.get(2, 1) * mfY +
-                rMat.get(2, 2));
-
-            if(!fTools::equalZero(fTempM) && !fTools::equal(fOne, fTempM))
-            {
-                fTempX /= fTempM;
-                fTempY /= fTempM;
-            }
-        }
-
         mfX = fTempX;
         mfY = fTempY;
 
diff --git a/basegfx/source/point/b2ipoint.cxx 
b/basegfx/source/point/b2ipoint.cxx
index 7b43ebc860e2..2790fe3a18a8 100644
--- a/basegfx/source/point/b2ipoint.cxx
+++ b/basegfx/source/point/b2ipoint.cxx
@@ -41,21 +41,6 @@ namespace basegfx
             rMat.get(1, 1) * mnY +
             rMat.get(1, 2));
 
-        if(!rMat.isLastLineDefault())
-        {
-            const double fOne(1.0);
-            const double fTempM(
-                rMat.get(2, 0) * mnX +
-                rMat.get(2, 1) * mnY +
-                rMat.get(2, 2));
-
-            if(!fTools::equalZero(fTempM) && !fTools::equal(fOne, fTempM))
-            {
-                fTempX /= fTempM;
-                fTempY /= fTempM;
-            }
-        }
-
         mnX = fround(fTempX);
         mnY = fround(fTempY);
 
diff --git a/basegfx/test/B2DHomMatrixTest.cxx 
b/basegfx/test/B2DHomMatrixTest.cxx
index bd6b1f8c8029..aace816d3e3a 100644
--- a/basegfx/test/B2DHomMatrixTest.cxx
+++ b/basegfx/test/B2DHomMatrixTest.cxx
@@ -79,9 +79,6 @@ public:
         maPerspective.set(1, 0, 4.0);
         maPerspective.set(1, 1, 5.0);
         maPerspective.set(1, 2, 6.0);
-        maPerspective.set(2, 0, 7.0);
-        maPerspective.set(2, 1, 8.0);
-        maPerspective.set(2, 2, 9.0);
     }
 
     void equal()
@@ -129,9 +126,6 @@ public:
         aPerspective.set(1, 0, 4.0);
         aPerspective.set(1, 1, 5.0);
         aPerspective.set(1, 2, 6.0);
-        aPerspective.set(2, 0, 7.0);
-        aPerspective.set(2, 1, 8.0);
-        aPerspective.set(2, 2, 9.0);
 
         CPPUNIT_ASSERT_MESSAGE("operator==: identity matrix", 
aIdentity.operator==(maIdentity));
         CPPUNIT_ASSERT_MESSAGE("operator==: scale matrix", 
aScale.operator==(maScale));
@@ -239,59 +233,11 @@ public:
         affineAffineProd.set(1, 1, 33);
         affineAffineProd.set(1, 2, 48);
 
-        B2DHomMatrix affinePerspectiveProd;
-
-        affinePerspectiveProd.set(0, 0, 30);
-        affinePerspectiveProd.set(0, 1, 36);
-        affinePerspectiveProd.set(0, 2, 42);
-        affinePerspectiveProd.set(1, 0, 66);
-        affinePerspectiveProd.set(1, 1, 81);
-        affinePerspectiveProd.set(1, 2, 96);
-        affinePerspectiveProd.set(2, 0, 7);
-        affinePerspectiveProd.set(2, 1, 8);
-        affinePerspectiveProd.set(2, 2, 9);
-
-        B2DHomMatrix perspectiveAffineProd;
-
-        perspectiveAffineProd.set(0, 0, 9);
-        perspectiveAffineProd.set(0, 1, 12);
-        perspectiveAffineProd.set(0, 2, 18);
-        perspectiveAffineProd.set(1, 0, 24);
-        perspectiveAffineProd.set(1, 1, 33);
-        perspectiveAffineProd.set(1, 2, 48);
-        perspectiveAffineProd.set(2, 0, 39);
-        perspectiveAffineProd.set(2, 1, 54);
-        perspectiveAffineProd.set(2, 2, 78);
-
-        B2DHomMatrix perspectivePerspectiveProd;
-
-        perspectivePerspectiveProd.set(0, 0, 30);
-        perspectivePerspectiveProd.set(0, 1, 36);
-        perspectivePerspectiveProd.set(0, 2, 42);
-        perspectivePerspectiveProd.set(1, 0, 66);
-        perspectivePerspectiveProd.set(1, 1, 81);
-        perspectivePerspectiveProd.set(1, 2, 96);
-        perspectivePerspectiveProd.set(2, 0, 102);
-        perspectivePerspectiveProd.set(2, 1, 126);
-        perspectivePerspectiveProd.set(2, 2, 150);
-
         B2DHomMatrix temp;
 
         temp = maAffine;
         temp *= maAffine;
         CPPUNIT_ASSERT_EQUAL_MESSAGE("multiply: both compact", 
affineAffineProd, temp);
-
-        temp = maPerspective;
-        temp *= maAffine;
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("multiply: first compact", 
affinePerspectiveProd, temp);
-
-        temp = maAffine;
-        temp *= maPerspective;
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("multiply: second compact", 
perspectiveAffineProd, temp);
-
-        temp = maPerspective;
-        temp *= maPerspective;
-        CPPUNIT_ASSERT_EQUAL_MESSAGE("multiply: none compact", 
perspectivePerspectiveProd, temp);
     }
 
     void impFillMatrix(B2DHomMatrix& rSource, double fScaleX, double fScaleY, 
double fShearX,
diff --git a/chart2/source/tools/CommonConverters.cxx 
b/chart2/source/tools/CommonConverters.cxx
index 50b08397e1d4..293fa7b11ddf 100644
--- a/chart2/source/tools/CommonConverters.cxx
+++ b/chart2/source/tools/CommonConverters.cxx
@@ -92,9 +92,10 @@ drawing::HomogenMatrix B3DHomMatrixToHomogenMatrix( const 
::basegfx::B3DHomMatri
     aM.set(1, 0, rM.get(1, 0));
     aM.set(1, 1, rM.get(1, 1));
     aM.set(1, 2, rM.get(1, 3));
-    aM.set(2, 0, rM.get(3, 0));
-    aM.set(2, 1, rM.get(3, 1));
-    aM.set(2, 2, rM.get(3, 3));
+    // For this to be a valid 2D transform matrix, the last row must be [0,0,1]
+    assert( rM.get(3, 0) == 0 );
+    assert( rM.get(3, 1) == 0 );
+    assert( rM.get(3, 3) == 1 );
     return aM;
 }
 
@@ -107,9 +108,9 @@ drawing::HomogenMatrix3 B2DHomMatrixToHomogenMatrix3( const 
::basegfx::B2DHomMat
     aHM.Line2.Column1 = rM.get(1, 0);
     aHM.Line2.Column2 = rM.get(1, 1);
     aHM.Line2.Column3 = rM.get(1, 2);
-    aHM.Line3.Column1 = rM.get(2, 0);
-    aHM.Line3.Column2 = rM.get(2, 1);
-    aHM.Line3.Column3 = rM.get(2, 2);
+    aHM.Line3.Column1 = 0;
+    aHM.Line3.Column2 = 0;
+    aHM.Line3.Column3 = 1;
     return aHM;
 }
 
diff --git a/drawinglayer/source/texture/texture.cxx 
b/drawinglayer/source/texture/texture.cxx
index 5176838d610e..ccfaa13bd8bf 100644
--- a/drawinglayer/source/texture/texture.cxx
+++ b/drawinglayer/source/texture/texture.cxx
@@ -944,20 +944,6 @@ namespace drawinglayer::texture
                 rMat.get(1, 1) * fY +
                 rMat.get(1, 2));
 
-            if(!rMat.isLastLineDefault())
-            {
-                const double fOne(1.0);
-                const double fTempM(
-                    rMat.get(2, 0) * fX +
-                    rMat.get(2, 1) * fY +
-                    rMat.get(2, 2));
-
-                if(!basegfx::fTools::equalZero(fTempM) && 
!basegfx::fTools::equal(fOne, fTempM))
-                {
-                    fTempY /= fTempM;
-                }
-            }
-
             return fmod(fTempY, mfDistance);
         }
 
diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx 
b/drawinglayer/source/tools/primitive2dxmldump.cxx
index 08f585a3638b..2267a1080c13 100644
--- a/drawinglayer/source/tools/primitive2dxmldump.cxx
+++ b/drawinglayer/source/tools/primitive2dxmldump.cxx
@@ -81,9 +81,9 @@ void writeMatrix(::tools::XmlWriter& rWriter, const 
basegfx::B2DHomMatrix& rMatr
     rWriter.attribute("xy21", rMatrix.get(1, 0));
     rWriter.attribute("xy22", rMatrix.get(1, 1));
     rWriter.attribute("xy23", rMatrix.get(1, 2));
-    rWriter.attribute("xy31", rMatrix.get(2, 0));
-    rWriter.attribute("xy32", rMatrix.get(2, 1));
-    rWriter.attribute("xy33", rMatrix.get(2, 2));
+    rWriter.attribute("xy31", 0);
+    rWriter.attribute("xy32", 0);
+    rWriter.attribute("xy33", 1);
 }
 
 void writeMatrix3D(::tools::XmlWriter& rWriter, const basegfx::B3DHomMatrix& 
rMatrix)
diff --git a/filter/source/msfilter/eschesdo.cxx 
b/filter/source/msfilter/eschesdo.cxx
index 8c39297f1e59..efe6cdfaa495 100644
--- a/filter/source/msfilter/eschesdo.cxx
+++ b/filter/source/msfilter/eschesdo.cxx
@@ -1090,9 +1090,10 @@ static basegfx::B2DRange 
getUnrotatedGroupBoundRange(const Reference< XShape >&
                             aHomogenMatrix.set(1, 0, aMatrix.Line2.Column1);
                             aHomogenMatrix.set(1, 1, aMatrix.Line2.Column2);
                             aHomogenMatrix.set(1, 2, aMatrix.Line2.Column3);
-                            aHomogenMatrix.set(2, 0, aMatrix.Line3.Column1);
-                            aHomogenMatrix.set(2, 1, aMatrix.Line3.Column2);
-                            aHomogenMatrix.set(2, 2, aMatrix.Line3.Column3);
+                            // For this to be a valid 2D transform matrix, the 
last row must be [0,0,1]
+                            assert( aMatrix.Line3.Column1 == 0 );
+                            assert( aMatrix.Line3.Column2 == 0 );
+                            assert( aMatrix.Line3.Column3 == 1 );
 
                             basegfx::B2DVector aScale, aTranslate;
                             double fRotate, fShearX;
diff --git a/include/basegfx/matrix/b2dhommatrix.hxx 
b/include/basegfx/matrix/b2dhommatrix.hxx
index e1fbf60dee1a..19660f786c99 100644
--- a/include/basegfx/matrix/b2dhommatrix.hxx
+++ b/include/basegfx/matrix/b2dhommatrix.hxx
@@ -26,22 +26,35 @@
 #include <sal/types.h>
 #include <basegfx/basegfxdllapi.h>
 #include <basegfx/matrix/hommatrixtemplate.hxx>
+#include <array>
 
 namespace basegfx
 {
     class B2DTuple;
 
-    using Impl2DHomMatrix = ::basegfx::internal::ImplHomMatrixTemplate< 3 >;
-
     class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC B2DHomMatrix
     {
     private:
-        Impl2DHomMatrix maImpl;
+        // Since this is a graphics matrix, the last row is always 0 0 1, so 
we don't bother to store it.
+        std::array<std::array<double, 3>, 2> mfValues {
+            std::array<double, 3>{ 1.0, 0.0, 0.0 },
+            std::array<double, 3>{ 0.0, 1.0, 0.0 } };
 
     public:
-        B2DHomMatrix() {}
-        B2DHomMatrix(const B2DHomMatrix& rMat) = default;
-        B2DHomMatrix(B2DHomMatrix&& rMat) = default;
+        constexpr B2DHomMatrix() = default;
+
+        /** constructor to allow setting all needed values for a 3x2 matrix at 
once. The
+            parameter f_0x1 e.g. is the same as using set(0, 1, f)
+         */
+        constexpr B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, 
double f_1x0, double f_1x1, double f_1x2)
+        {
+            mfValues[0][0] = f_0x0;
+            mfValues[0][1] = f_0x1;
+            mfValues[0][2] = f_0x2;
+            mfValues[1][0] = f_1x0;
+            mfValues[1][1] = f_1x1;
+            mfValues[1][2] = f_1x2;
+        }
 
         /** Convenience creator for declaration of the matrix that is commonly
             used by web standards (SVG, CSS, HTML).
@@ -70,27 +83,21 @@ namespace basegfx
         // Convenience accessor for value at 1,2 position in the matrix
         double f() const { return get(1,2); }
 
-        /** constructor to allow setting all needed values for a 3x2 matrix at 
once. The
-            parameter f_0x1 e.g. is the same as using set(0, 1, f)
-         */
-        B2DHomMatrix(double f_0x0, double f_0x1, double f_0x2, double f_1x0, 
double f_1x1, double f_1x2);
-
         double get(sal_uInt16 nRow, sal_uInt16 nColumn) const
         {
-            return maImpl.get(nRow, nColumn);
+            return mfValues[nRow][nColumn];
         }
 
-        void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue);
+        void set(sal_uInt16 nRow, sal_uInt16 nColumn, double fValue)
+        {
+            mfValues[nRow][nColumn] = fValue;
+        }
 
         /** allow setting all needed values for a 3x2 matrix in one call. The
             parameter f_0x1 e.g. is the same as using set(0, 1, f)
          */
         void set3x2(double f_0x0, double f_0x1, double f_0x2, double f_1x0, 
double f_1x1, double f_1x2);
 
-        // test if last line is default to see if last line needs to be
-        // involved in calculations
-        bool isLastLineDefault() const;
-
         // reset to a standard matrix
         bool isIdentity() const;
         void identity();
@@ -110,22 +117,12 @@ namespace basegfx
         void shearX(double fSx);
         void shearY(double fSy);
 
-        B2DHomMatrix& operator+=(const B2DHomMatrix& rMat);
-        B2DHomMatrix& operator-=(const B2DHomMatrix& rMat);
-
         bool operator==(const B2DHomMatrix& rMat) const;
         bool operator!=(const B2DHomMatrix& rMat) const;
 
-        B2DHomMatrix& operator*=(double fValue);
-        B2DHomMatrix& operator/=(double fValue);
-
         // matrix multiplication from the left to the local
         B2DHomMatrix& operator*=(const B2DHomMatrix& rMat);
 
-        // assignment operator
-        B2DHomMatrix& operator=(const B2DHomMatrix& rMat) = default;
-        B2DHomMatrix& operator=(B2DHomMatrix&& rMat) = default;
-
         /**
          * Help routine to decompose given homogen 3x3 matrix to components. A 
correction of the
          * components is done to avoid inaccuracies.
@@ -134,6 +131,11 @@ namespace basegfx
          * compose a homogen 3x3 matrix from components.
          */
         bool decompose(B2DTuple& rScale, B2DTuple& rTranslate, double& 
rRotate, double& rShearX) const;
+
+    private:
+        void computeAdjoint(double (&dst)[6]) const;
+        double computeDeterminant(double (&dst)[6]) const;
+        void doMulMatrix(const B2DHomMatrix& rMat);
     };
 
     inline B2DHomMatrix operator*(const B2DHomMatrix& rMatA, const 
B2DHomMatrix& rMatB)
@@ -150,9 +152,7 @@ namespace basegfx
         return stream
             << '[' << matrix.get(0, 0) << ' ' << matrix.get(0, 1) << ' '
             << matrix.get(0, 2) << "; " << matrix.get(1, 0) << ' '
-            << matrix.get(1, 1) << ' ' << matrix.get(1, 2) << "; "
-            << matrix.get(2, 0) << ' ' << matrix.get(2, 1) << ' '
-            << matrix.get(2, 2) << ']';
+            << matrix.get(1, 1) << ' ' << matrix.get(1, 2) << ']';
     }
 } // end of namespace basegfx
 
diff --git a/oox/source/drawingml/shape.cxx b/oox/source/drawingml/shape.cxx
index 9417551b0f86..b9aebab1b31d 100644
--- a/oox/source/drawingml/shape.cxx
+++ b/oox/source/drawingml/shape.cxx
@@ -1118,9 +1118,9 @@ Reference< XShape > const & Shape::createAndInsert(
         aMatrix.Line2.Column2 = aTransformation.get(1,1);
         aMatrix.Line2.Column3 = aTransformation.get(1,2);
 
-        aMatrix.Line3.Column1 = aTransformation.get(2,0);
-        aMatrix.Line3.Column2 = aTransformation.get(2,1);
-        aMatrix.Line3.Column3 = aTransformation.get(2,2);
+        aMatrix.Line3.Column1 = 0;
+        aMatrix.Line3.Column2 = 0;
+        aMatrix.Line3.Column3 = 1;
 
         maShapeProperties.setProperty(PROP_Transformation, aMatrix);
     }
diff --git a/oox/source/shape/WpsContext.cxx b/oox/source/shape/WpsContext.cxx
index 8e0cb8b544df..beaefc33fbbc 100644
--- a/oox/source/shape/WpsContext.cxx
+++ b/oox/source/shape/WpsContext.cxx
@@ -606,9 +606,10 @@ oox::core::ContextHandlerRef 
WpsContext::onCreateContext(sal_Int32 nElementToken
                     aTransformation.set(1, 0, aMatrix.Line2.Column1);
                     aTransformation.set(1, 1, aMatrix.Line2.Column2);
                     aTransformation.set(1, 2, aMatrix.Line2.Column3);
-                    aTransformation.set(2, 0, aMatrix.Line3.Column1);
-                    aTransformation.set(2, 1, aMatrix.Line3.Column2);
-                    aTransformation.set(2, 2, aMatrix.Line3.Column3);
+                    // For this to be a valid 2D transform matrix, the last 
row must be [0,0,1]
+                    assert(aMatrix.Line3.Column1 == 0);
+                    assert(aMatrix.Line3.Column2 == 0);
+                    assert(aMatrix.Line3.Column3 == 1);
                     basegfx::B2DTuple aScale;
                     basegfx::B2DTuple aTranslate;
                     double fRotate = 0;
diff --git a/svx/source/unodraw/unoshape.cxx b/svx/source/unodraw/unoshape.cxx
index f46727299cef..8494f493513d 100644
--- a/svx/source/unodraw/unoshape.cxx
+++ b/svx/source/unodraw/unoshape.cxx
@@ -2076,9 +2076,10 @@ bool SvxShape::setPropertyValueImpl( const OUString&, 
const SfxItemPropertyMapEn
             aNewHomogenMatrix.set(1, 0, aMatrix.Line2.Column1);
             aNewHomogenMatrix.set(1, 1, aMatrix.Line2.Column2);
             aNewHomogenMatrix.set(1, 2, aMatrix.Line2.Column3);
-            aNewHomogenMatrix.set(2, 0, aMatrix.Line3.Column1);
-            aNewHomogenMatrix.set(2, 1, aMatrix.Line3.Column2);
-            aNewHomogenMatrix.set(2, 2, aMatrix.Line3.Column3);
+            // For this to be a valid 2D transform matrix, the last row must 
be [0,0,1]
+            assert( aMatrix.Line3.Column1 == 0 );
+            assert( aMatrix.Line3.Column2 == 0 );
+            assert( aMatrix.Line3.Column3 == 1 );
 
             // tdf#117145 metric of SdrModel is app-specific, metric of UNO 
API is 100thmm
             // Need to adapt aNewHomogenMatrix from 100thmm to app-specific
@@ -2578,9 +2579,9 @@ bool SvxShape::getPropertyValueImpl( const OUString&, 
const SfxItemPropertyMapEn
         aMatrix.Line2.Column1 = aNewHomogenMatrix.get(1, 0);
         aMatrix.Line2.Column2 = aNewHomogenMatrix.get(1, 1);
         aMatrix.Line2.Column3 = aNewHomogenMatrix.get(1, 2);
-        aMatrix.Line3.Column1 = aNewHomogenMatrix.get(2, 0);
-        aMatrix.Line3.Column2 = aNewHomogenMatrix.get(2, 1);
-        aMatrix.Line3.Column3 = aNewHomogenMatrix.get(2, 2);
+        aMatrix.Line3.Column1 = 0;
+        aMatrix.Line3.Column2 = 0;
+        aMatrix.Line3.Column3 = 1;
 
         rValue <<= aMatrix;
 
diff --git a/sw/source/core/edit/edfcol.cxx b/sw/source/core/edit/edfcol.cxx
index 47b4eb61684d..1be771b89174 100644
--- a/sw/source/core/edit/edfcol.cxx
+++ b/sw/source/core/edit/edfcol.cxx
@@ -1379,9 +1379,10 @@ static sal_Int16 lcl_GetAngle(const 
drawing::HomogenMatrix3& rMatrix)
     aTransformation.set(1, 0, rMatrix.Line2.Column1);
     aTransformation.set(1, 1, rMatrix.Line2.Column2);
     aTransformation.set(1, 2, rMatrix.Line2.Column3);
-    aTransformation.set(2, 0, rMatrix.Line3.Column1);
-    aTransformation.set(2, 1, rMatrix.Line3.Column2);
-    aTransformation.set(2, 2, rMatrix.Line3.Column3);
+    // For this to be a valid 2D transform matrix, the last row must be [0,0,1]
+    assert( rMatrix.Line3.Column1 == 0 );
+    assert( rMatrix.Line3.Column2 == 0 );
+    assert( rMatrix.Line3.Column3 == 1 );
 
     aTransformation.decompose(aScale, aTranslate, fRotate, fShear);
     sal_Int16 nDeg = round(basegfx::rad2deg(fRotate));
@@ -1553,9 +1554,9 @@ static void lcl_placeWatermarkInHeader(const 
SfxWatermarkItem& rWatermark,
     aMatrix.Line2.Column1 = aTransformation.get(1, 0);
     aMatrix.Line2.Column2 = aTransformation.get(1, 1);
     aMatrix.Line2.Column3 = aTransformation.get(1, 2);
-    aMatrix.Line3.Column1 = aTransformation.get(2, 0);
-    aMatrix.Line3.Column2 = aTransformation.get(2, 1);
-    aMatrix.Line3.Column3 = aTransformation.get(2, 2);
+    aMatrix.Line3.Column1 = 0;
+    aMatrix.Line3.Column2 = 0;
+    aMatrix.Line3.Column3 = 1;
     uno::Reference<beans::XPropertySet> xPropertySet(xShape, uno::UNO_QUERY);
     xPropertySet->setPropertyValue(UNO_NAME_ANCHOR_TYPE, 
uno::Any(text::TextContentAnchorType_AT_CHARACTER));
     uno::Reference<text::XTextContent> xTextContent(xShape, uno::UNO_QUERY);
diff --git a/sw/source/core/unocore/unodraw.cxx 
b/sw/source/core/unocore/unodraw.cxx
index a096f4f12268..cda4850d8671 100644
--- a/sw/source/core/unocore/unodraw.cxx
+++ b/sw/source/core/unocore/unodraw.cxx
@@ -2553,9 +2553,10 @@ drawing::HomogenMatrix3 
SwXShape::ConvertTransformationToLayoutDir(
                 aTempMatrix.set(1, 0, aMatrix.Line2.Column1 );
                 aTempMatrix.set(1, 1, aMatrix.Line2.Column2 );
                 aTempMatrix.set(1, 2, aMatrix.Line2.Column3 );
-                aTempMatrix.set(2, 0, aMatrix.Line3.Column1 );
-                aTempMatrix.set(2, 1, aMatrix.Line3.Column2 );
-                aTempMatrix.set(2, 2, aMatrix.Line3.Column3 );
+                // For this to be a valid 2D transform matrix, the last row 
must be [0,0,1]
+                assert( aMatrix.Line3.Column1 == 0 );
+                assert( aMatrix.Line3.Column2 == 0 );
+                assert( aMatrix.Line3.Column3 == 1 );
                 // #i73079#
                 aTempMatrix.translate( aTranslateDiff.X, aTranslateDiff.Y );
                 aMatrix.Line1.Column1 = aTempMatrix.get(0, 0);
@@ -2564,9 +2565,9 @@ drawing::HomogenMatrix3 
SwXShape::ConvertTransformationToLayoutDir(
                 aMatrix.Line2.Column1 = aTempMatrix.get(1, 0);
                 aMatrix.Line2.Column2 = aTempMatrix.get(1, 1);
                 aMatrix.Line2.Column3 = aTempMatrix.get(1, 2);
-                aMatrix.Line3.Column1 = aTempMatrix.get(2, 0);
-                aMatrix.Line3.Column2 = aTempMatrix.get(2, 1);
-                aMatrix.Line3.Column3 = aTempMatrix.get(2, 2);
+                aMatrix.Line3.Column1 = 0;
+                aMatrix.Line3.Column2 = 0;
+                aMatrix.Line3.Column3 = 1;
             }
         }
     }
diff --git a/xmloff/source/draw/shapeexport.cxx 
b/xmloff/source/draw/shapeexport.cxx
index 7f19e7fe3688..51976a625c97 100644
--- a/xmloff/source/draw/shapeexport.cxx
+++ b/xmloff/source/draw/shapeexport.cxx
@@ -1513,9 +1513,10 @@ void 
XMLShapeExport::ImpExportNewTrans_GetB2DHomMatrix(::basegfx::B2DHomMatrix&
     rMatrix.set(1, 0, aMatrix.Line2.Column1);
     rMatrix.set(1, 1, aMatrix.Line2.Column2);
     rMatrix.set(1, 2, aMatrix.Line2.Column3);
-    rMatrix.set(2, 0, aMatrix.Line3.Column1);
-    rMatrix.set(2, 1, aMatrix.Line3.Column2);
-    rMatrix.set(2, 2, aMatrix.Line3.Column3);
+    // For this to be a valid 2D transform matrix, the last row must be [0,0,1]
+    assert( aMatrix.Line3.Column1 == 0 );
+    assert( aMatrix.Line3.Column2 == 0 );
+    assert( aMatrix.Line3.Column3 == 1 );
 }
 
 void XMLShapeExport::ImpExportNewTrans_DecomposeAndRefPoint(const 
::basegfx::B2DHomMatrix& rMatrix, ::basegfx::B2DTuple& rTRScale,
diff --git a/xmloff/source/draw/ximpshap.cxx b/xmloff/source/draw/ximpshap.cxx
index 74d5027e7c11..5e965eba5aaa 100644
--- a/xmloff/source/draw/ximpshap.cxx
+++ b/xmloff/source/draw/ximpshap.cxx
@@ -590,9 +590,9 @@ void SdXMLShapeContext::SetTransformation()
     aUnoMatrix.Line2.Column2 = aB2DHomMatrix.get(1, 1);
     aUnoMatrix.Line2.Column3 = aB2DHomMatrix.get(1, 2);
 
-    aUnoMatrix.Line3.Column1 = aB2DHomMatrix.get(2, 0);
-    aUnoMatrix.Line3.Column2 = aB2DHomMatrix.get(2, 1);
-    aUnoMatrix.Line3.Column3 = aB2DHomMatrix.get(2, 2);
+    aUnoMatrix.Line3.Column1 = 0;
+    aUnoMatrix.Line3.Column2 = 0;
+    aUnoMatrix.Line3.Column3 = 1;
 
     xPropSet->setPropertyValue("Transformation", Any(aUnoMatrix));
 }

Reply via email to