basegfx/source/color/bcolormodifier.cxx         |   32 +++++++++
 basegfx/test/BColorModifierTest.cxx             |   85 ++++++++++++++++++++++++
 include/basegfx/color/bcolormodifier.hxx        |   28 +++++++
 svgio/inc/svgfecolormatrixnode.hxx              |    3 
 svgio/inc/svgtools.hxx                          |    2 
 svgio/qa/cppunit/SvgImportTest.cxx              |    8 +-
 svgio/source/svgreader/svgfecolormatrixnode.cxx |   13 +++
 svgio/source/svgreader/svgtools.cxx             |   34 +++++++++
 8 files changed, 200 insertions(+), 5 deletions(-)

New commits:
commit 8395acfec900ea23d25632909eb22e02763bbe37
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Fri Jun 16 11:50:57 2023 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Jun 22 20:58:09 2023 +0200

    tdf#155735: Add support for matrix type
    
    Change-Id: Icc172c5f47731ddcf0beca64c72c2022313e74a7
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153177
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit 40371d9fe99d9588e2717b24e44b1ff846e6fe7e)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153425

diff --git a/basegfx/source/color/bcolormodifier.cxx 
b/basegfx/source/color/bcolormodifier.cxx
index 8d6f99a3faf5..829b0abda659 100644
--- a/basegfx/source/color/bcolormodifier.cxx
+++ b/basegfx/source/color/bcolormodifier.cxx
@@ -142,6 +142,38 @@ namespace basegfx
         return "interpolate";
     }
 
+    BColorModifier_matrix::~BColorModifier_matrix()
+    {
+    }
+
+    bool BColorModifier_matrix::operator==(const BColorModifier& rCompare) 
const
+    {
+        const BColorModifier_matrix* pCompare = dynamic_cast< const 
BColorModifier_matrix* >(&rCompare);
+
+        if(!pCompare)
+        {
+            return false;
+        }
+
+        return maMatrix == pCompare->maMatrix;
+    }
+
+    ::basegfx::BColor BColorModifier_matrix::getModifiedColor(const 
::basegfx::BColor& aSourceColor) const
+    {
+        basegfx::B3DHomMatrix aColorMatrix;
+        aColorMatrix.set(0, 0, aSourceColor.getRed());
+        aColorMatrix.set(1, 0, aSourceColor.getGreen());
+        aColorMatrix.set(2, 0, aSourceColor.getBlue());
+
+        aColorMatrix = maMatrix * aColorMatrix;
+        return ::basegfx::BColor(aColorMatrix.get(0, 0), aColorMatrix.get(1, 
0), aColorMatrix.get(2, 0));
+    }
+
+    OUString BColorModifier_matrix::getModifierName() const
+    {
+        return "matrix";
+    }
+
     BColorModifier_saturate::BColorModifier_saturate(double fValue)
     {
         maSatMatrix.set(0, 0, 0.213 + 0.787 * fValue);
diff --git a/basegfx/test/BColorModifierTest.cxx 
b/basegfx/test/BColorModifierTest.cxx
index d6e0648d2c17..17b6a0c22257 100755
--- a/basegfx/test/BColorModifierTest.cxx
+++ b/basegfx/test/BColorModifierTest.cxx
@@ -269,6 +269,89 @@ public:
         CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2));
     }
 
+    void testMatrix()
+    {
+        // green matrix
+        basegfx::B3DHomMatrix aMatrix;
+        aMatrix.set(0, 0, 0.0);
+        aMatrix.set(0, 1, 0.0);
+        aMatrix.set(0, 2, 0.0);
+        aMatrix.set(0, 3, 0.0);
+        aMatrix.set(1, 0, 1.0);
+        aMatrix.set(1, 1, 1.0);
+        aMatrix.set(1, 2, 1.0);
+        aMatrix.set(1, 3, 1.0);
+        aMatrix.set(2, 0, 0.0);
+        aMatrix.set(2, 1, 0.0);
+        aMatrix.set(2, 2, 0.0);
+        aMatrix.set(2, 3, 0.0);
+
+        const basegfx::BColorModifierSharedPtr aBColorModifier
+            = std::make_shared<basegfx::BColorModifier_matrix>(aMatrix);
+
+        BColor aExpectedWhite(0.0, 3.0, 0.0);
+        CPPUNIT_ASSERT_EQUAL(aExpectedWhite, 
aBColorModifier->getModifiedColor(maWhite));
+        BColor aExpectedGray(0.0, 1.5, 0.0);
+        CPPUNIT_ASSERT_EQUAL(aExpectedGray, 
aBColorModifier->getModifiedColor(maGray));
+        CPPUNIT_ASSERT_EQUAL(maBlack, 
aBColorModifier->getModifiedColor(maBlack));
+
+        CPPUNIT_ASSERT_EQUAL(maGreen, 
aBColorModifier->getModifiedColor(maRed));
+        CPPUNIT_ASSERT_EQUAL(maGreen, 
aBColorModifier->getModifiedColor(maGreen));
+        CPPUNIT_ASSERT_EQUAL(maGreen, 
aBColorModifier->getModifiedColor(maBlue));
+        BColor aExpectedYellow(0.0, 2.0, 0.0);
+        CPPUNIT_ASSERT_EQUAL(aExpectedYellow, 
aBColorModifier->getModifiedColor(maYellow));
+        BColor aExpectedMagenta = aExpectedYellow;
+        CPPUNIT_ASSERT_EQUAL(aExpectedMagenta, 
aBColorModifier->getModifiedColor(maMagenta));
+        BColor aExpectedCyan = aExpectedYellow;
+        CPPUNIT_ASSERT_EQUAL(aExpectedCyan, 
aBColorModifier->getModifiedColor(maCyan));
+
+        CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier));
+        const basegfx::BColorModifierSharedPtr aBColorModifierInvert
+            = std::make_shared<basegfx::BColorModifier_invert>();
+        CPPUNIT_ASSERT(*aBColorModifier != *aBColorModifierInvert);
+
+        const basegfx::BColorModifierSharedPtr aBColorModifier2
+            = std::make_shared<basegfx::BColorModifier_matrix>(aMatrix);
+        CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2));
+    }
+
+    void testIdentityMatrix()
+    {
+        basegfx::B3DHomMatrix aMatrix;
+        aMatrix.set(0, 0, 1.0);
+        aMatrix.set(0, 1, 0.0);
+        aMatrix.set(0, 2, 0.0);
+        aMatrix.set(1, 0, 0.0);
+        aMatrix.set(1, 1, 1.0);
+        aMatrix.set(1, 2, 0.0);
+        aMatrix.set(2, 0, 0.0);
+        aMatrix.set(2, 1, 0.0);
+        aMatrix.set(2, 2, 1.0);
+
+        const basegfx::BColorModifierSharedPtr aBColorModifier
+            = std::make_shared<basegfx::BColorModifier_matrix>(aMatrix);
+
+        CPPUNIT_ASSERT_EQUAL(maWhite, 
aBColorModifier->getModifiedColor(maWhite));
+        CPPUNIT_ASSERT_EQUAL(maGray, 
aBColorModifier->getModifiedColor(maGray));
+        CPPUNIT_ASSERT_EQUAL(maBlack, 
aBColorModifier->getModifiedColor(maBlack));
+
+        CPPUNIT_ASSERT_EQUAL(maRed, aBColorModifier->getModifiedColor(maRed));
+        CPPUNIT_ASSERT_EQUAL(maGreen, 
aBColorModifier->getModifiedColor(maGreen));
+        CPPUNIT_ASSERT_EQUAL(maBlue, 
aBColorModifier->getModifiedColor(maBlue));
+        CPPUNIT_ASSERT_EQUAL(maYellow, 
aBColorModifier->getModifiedColor(maYellow));
+        CPPUNIT_ASSERT_EQUAL(maMagenta, 
aBColorModifier->getModifiedColor(maMagenta));
+        CPPUNIT_ASSERT_EQUAL(maCyan, 
aBColorModifier->getModifiedColor(maCyan));
+
+        CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier));
+        const basegfx::BColorModifierSharedPtr aBColorModifierInvert
+            = std::make_shared<basegfx::BColorModifier_invert>();
+        CPPUNIT_ASSERT(*aBColorModifier != *aBColorModifierInvert);
+
+        const basegfx::BColorModifierSharedPtr aBColorModifier2
+            = std::make_shared<basegfx::BColorModifier_matrix>(aMatrix);
+        CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2));
+    }
+
     CPPUNIT_TEST_SUITE(bcolormodifier);
     CPPUNIT_TEST(testGray);
     CPPUNIT_TEST(testInvert);
@@ -277,6 +360,8 @@ public:
     CPPUNIT_TEST(testSaturate);
     CPPUNIT_TEST(testLuminanceToAlpha);
     CPPUNIT_TEST(testHueRotate);
+    CPPUNIT_TEST(testMatrix);
+    CPPUNIT_TEST(testIdentityMatrix);
     CPPUNIT_TEST_SUITE_END();
 };
 
diff --git a/include/basegfx/color/bcolormodifier.hxx 
b/include/basegfx/color/bcolormodifier.hxx
index 5a3ca0a78adf..ceffae841847 100644
--- a/include/basegfx/color/bcolormodifier.hxx
+++ b/include/basegfx/color/bcolormodifier.hxx
@@ -21,6 +21,7 @@
 
 #include <config_options.h>
 #include <basegfx/basegfxdllapi.h>
+#include <basegfx/matrix/b3dhommatrix.hxx>
 #include <basegfx/color/bcolor.hxx>
 #include <basegfx/matrix/b3dhommatrix.hxx>
 #include <rtl/ustring.hxx>
@@ -236,6 +237,33 @@ namespace basegfx
         SAL_DLLPRIVATE virtual OUString getModifierName() const override;
     };
 
+    /** Apply matrix
+        This derivation is used for the svg importer and does exactly what SVG
+        defines for this needed case.
+
+        See:
+        https://www.w3.org/TR/filter-effects/#elementdef-fecolormatrix
+    */
+    class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_matrix final : 
public BColorModifier
+    {
+    private:
+        basegfx::B3DHomMatrix       maMatrix;
+
+    public:
+        BColorModifier_matrix(basegfx::B3DHomMatrix aMatrix)
+        :   maMatrix(aMatrix)
+        {
+        }
+
+        virtual ~BColorModifier_matrix() override;
+
+        // compare operator
+        SAL_DLLPRIVATE virtual bool operator==(const BColorModifier& rCompare) 
const override;
+        // compute modified color
+        SAL_DLLPRIVATE virtual ::basegfx::BColor getModifiedColor(const 
::basegfx::BColor& aSourceColor) const override;
+        SAL_DLLPRIVATE virtual OUString getModifierName() const override;
+    };
+
     /** Apply hueRotate
         This derivation is used for the svg importer and does exactly what SVG
         defines for this needed case.
diff --git a/svgio/inc/svgfecolormatrixnode.hxx 
b/svgio/inc/svgfecolormatrixnode.hxx
index a63d44715457..78d8b027f653 100644
--- a/svgio/inc/svgfecolormatrixnode.hxx
+++ b/svgio/inc/svgfecolormatrixnode.hxx
@@ -21,7 +21,7 @@
 
 #include "svgnode.hxx"
 #include "svgstyleattributes.hxx"
-#include <basegfx/matrix/b2dhommatrix.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
 
 namespace svgio::svgreader
 {
@@ -29,6 +29,7 @@ enum class ColorType
 {
     None,
     HueRotate,
+    Matrix,
     Saturate,
     LuminanceToAlpha
 };
diff --git a/svgio/inc/svgtools.hxx b/svgio/inc/svgtools.hxx
index fd9bdd396d9d..1bca409001b6 100644
--- a/svgio/inc/svgtools.hxx
+++ b/svgio/inc/svgtools.hxx
@@ -20,6 +20,7 @@
 #pragma once
 
 #include <basegfx/color/bcolor.hxx>
+#include <basegfx/range/b3drange.hxx>
 #include <basegfx/range/b2drange.hxx>
 #include <basegfx/vector/b2ivector.hxx>
 #include <rtl/ustrbuf.hxx>
@@ -109,6 +110,7 @@ namespace svgio::svgreader
         bool match_colorKeyword(basegfx::BColor& rColor, const OUString& 
rName);
         bool read_color(const OUString& rCandidate, basegfx::BColor& rColor, 
SvgNumber& rOpacity);
         basegfx::B2DRange readViewBox(std::u16string_view rCandidate, 
InfoProvider const & rInfoProvider);
+        basegfx::B3DHomMatrix readFilterMatrix(std::u16string_view rCandidate, 
InfoProvider const & rInfoProvider);
         basegfx::B2DHomMatrix readTransform(std::u16string_view rCandidate, 
InfoProvider const & rInfoProvider);
         bool readSingleNumber(std::u16string_view rCandidate, SvgNumber& aNum);
         bool readLocalLink(std::u16string_view rCandidate, OUString& rURL);
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 87beb7742405..df1337090ff3 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -163,10 +163,10 @@ CPPUNIT_TEST_FIXTURE(Test, testFeColorMatrix)
 
     CPPUNIT_ASSERT (pDocument);
 
-    //assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor", 
"modifier", "matrix");
-    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[1]", 
"modifier", "saturate");
-    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[2]", 
"modifier", "hueRotate");
-    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[3]", 
"modifier", "luminance_to_alpha");
+    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[1]", 
"modifier", "matrix");
+    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[2]", 
"modifier", "saturate");
+    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[3]", 
"modifier", "hueRotate");
+    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[4]", 
"modifier", "luminance_to_alpha");
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testFilterFeGaussianBlur)
diff --git a/svgio/source/svgreader/svgfecolormatrixnode.cxx 
b/svgio/source/svgreader/svgfecolormatrixnode.cxx
index 42611e48efdd..5f8e03c4318b 100644
--- a/svgio/source/svgreader/svgfecolormatrixnode.cxx
+++ b/svgio/source/svgreader/svgfecolormatrixnode.cxx
@@ -53,6 +53,10 @@ void SvgFeColorMatrixNode::parseAttribute(const OUString& 
/*rTokenName*/, SVGTok
                 {
                     maType = ColorType::HueRotate;
                 }
+                else if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), 
u"matrix"))
+                {
+                    maType = ColorType::Matrix;
+                }
             }
             break;
         }
@@ -99,6 +103,15 @@ void 
SvgFeColorMatrixNode::apply(drawinglayer::primitive2d::Primitive2DContainer
                                         basegfx::deg2rad(aNum.getNumber()))));
         rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef };
     }
+    else if (maType == ColorType::Matrix)
+    {
+        basegfx::B3DHomMatrix aMatrix = readFilterMatrix(maValuesContent, 
*this);
+
+        const drawinglayer::primitive2d::Primitive2DReference xRef(
+            new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+                std::move(rTarget), 
std::make_shared<basegfx::BColorModifier_matrix>(aMatrix)));
+        rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef };
+    }
 }
 
 } // end of namespace svgio::svgreader
diff --git a/svgio/source/svgreader/svgtools.cxx 
b/svgio/source/svgreader/svgtools.cxx
index af10626af3ad..f885086497c1 100644
--- a/svgio/source/svgreader/svgtools.cxx
+++ b/svgio/source/svgreader/svgtools.cxx
@@ -24,6 +24,7 @@
 #include <o3tl/string_view.hxx>
 #include <basegfx/matrix/b2dhommatrix.hxx>
 #include <basegfx/matrix/b2dhommatrixtools.hxx>
+#include <basegfx/matrix/b3dhommatrix.hxx>
 #include <svgtoken.hxx>
 #include <unordered_map>
 
@@ -844,6 +845,39 @@ namespace svgio::svgreader
             return basegfx::B2DRange();
         }
 
+        basegfx::B3DHomMatrix readFilterMatrix(std::u16string_view rCandidate, 
InfoProvider const & rInfoProvider)
+        {
+            basegfx::B3DHomMatrix aMatrix;
+            const sal_Int32 nLen(rCandidate.size());
+
+            sal_Int32 nPos(0);
+            skip_char(rCandidate, ' ', ',', nPos, nLen);
+
+            SvgNumber aVal;
+
+            // create a 3x5 matrix using the first 15 values from the list of 
20 matrix values.
+            // FIXME: support alpha (the last 5 values)
+            for (sal_uInt16 nRow = 0; nRow < 3; ++nRow)
+            {
+                for (sal_uInt16 nColumn = 0; nColumn < 5; ++nColumn)
+                {
+                    // return earlier if there are not enough values
+                    if (nPos >= nLen)
+                    {
+                        return basegfx::B3DHomMatrix();
+                    }
+
+                    if(readNumberAndUnit(rCandidate, nPos, aVal, nLen))
+                    {
+                        aMatrix.set(nRow, nColumn, aVal.solve(rInfoProvider));
+                        skip_char(rCandidate, ' ', ',', nPos, nLen);
+                    }
+                }
+            }
+
+            return aMatrix;
+        }
+
         basegfx::B2DHomMatrix readTransform(std::u16string_view rCandidate, 
InfoProvider const & rInfoProvider)
         {
             basegfx::B2DHomMatrix aMatrix;

Reply via email to