basegfx/source/color/bcolormodifier.cxx         |   51 ++++++++++++++++++++++++
 basegfx/test/BColorModifierTest.cxx             |   33 +++++++++++++++
 include/basegfx/color/bcolormodifier.hxx        |   25 +++++++++++
 svgio/inc/svgfecolormatrixnode.hxx              |    3 -
 svgio/qa/cppunit/SvgImportTest.cxx              |    4 -
 svgio/source/svgreader/svgfecolormatrixnode.cxx |   27 ++++++++----
 6 files changed, 132 insertions(+), 11 deletions(-)

New commits:
commit cd3c376da36acf76327290b83eac8563f3bf562e
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Thu Jun 15 12:19:39 2023 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Jun 22 09:47:19 2023 +0200

    tdf#155735: Add support for hueRotate type
    
    Change-Id: I9c7ada2908c0739708fbc9e28ac58430350da7a9
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153112
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>
    (cherry picked from commit a62513e1e80e39f9928e9e1815a84761403a4f2b)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153420

diff --git a/basegfx/source/color/bcolormodifier.cxx 
b/basegfx/source/color/bcolormodifier.cxx
index 480af66e7588..8d6f99a3faf5 100644
--- a/basegfx/source/color/bcolormodifier.cxx
+++ b/basegfx/source/color/bcolormodifier.cxx
@@ -187,6 +187,57 @@ namespace basegfx
         return "saturate";
     }
 
+    BColorModifier_hueRotate::BColorModifier_hueRotate(double fRad)
+    {
+        const double fCos = cos(fRad);
+        const double fSin = sin(fRad);
+
+        maHueMatrix.set(0, 0, 0.213 + fCos * 0.787 - fSin * 0.213);
+        maHueMatrix.set(0, 1, 0.715 - fCos * 0.715 - fSin * 0.715);
+        maHueMatrix.set(0, 2, 0.072 - fCos * 0.072 + fSin * 0.928);
+        maHueMatrix.set(1, 0, 0.213 - fCos * 0.213 + fSin * 0.143);
+        maHueMatrix.set(1, 1, 0.715 + fCos * 0.285 + fSin * 0.140);
+        maHueMatrix.set(1, 2, 0.072 - fCos * 0.072 - fSin * 0.283);
+        maHueMatrix.set(2, 0, 0.213 - fCos * 0.213 - fSin * 0.787);
+        maHueMatrix.set(2, 1, 0.715 - fCos * 0.715 + fSin * 0.715);
+        maHueMatrix.set(2, 2, 0.072 + fCos * 0.928 + fSin * 0.072);
+    }
+
+    BColorModifier_hueRotate::~BColorModifier_hueRotate()
+    {
+    }
+
+    bool BColorModifier_hueRotate::operator==(const BColorModifier& rCompare) 
const
+    {
+        const BColorModifier_hueRotate* pCompare = dynamic_cast< const 
BColorModifier_hueRotate* >(&rCompare);
+
+        if(!pCompare)
+        {
+            return false;
+        }
+
+        return maHueMatrix == pCompare->maHueMatrix;
+    }
+
+    ::basegfx::BColor BColorModifier_hueRotate::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 = maHueMatrix * aColorMatrix;
+        return ::basegfx::BColor(
+                std::clamp(aColorMatrix.get(0, 0), 0.0, 1.0),
+                std::clamp(aColorMatrix.get(1, 0), 0.0, 1.0),
+                std::clamp(aColorMatrix.get(2, 0), 0.0, 1.0));
+    }
+
+    OUString BColorModifier_hueRotate::getModifierName() const
+    {
+        return "hueRotate";
+    }
+
     BColorModifier_black_and_white::~BColorModifier_black_and_white()
     {
     }
diff --git a/basegfx/test/BColorModifierTest.cxx 
b/basegfx/test/BColorModifierTest.cxx
index 053540018206..d6e0648d2c17 100755
--- a/basegfx/test/BColorModifierTest.cxx
+++ b/basegfx/test/BColorModifierTest.cxx
@@ -237,6 +237,38 @@ public:
         CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2));
     }
 
+    void testHueRotate()
+    {
+        const basegfx::BColorModifierSharedPtr aBColorModifier
+            = 
std::make_shared<basegfx::BColorModifier_hueRotate>(basegfx::deg2rad(180.0));
+
+        CPPUNIT_ASSERT_EQUAL(maWhite, 
aBColorModifier->getModifiedColor(maWhite));
+        CPPUNIT_ASSERT_EQUAL(maGray, 
aBColorModifier->getModifiedColor(maGray));
+        CPPUNIT_ASSERT_EQUAL(maBlack, 
aBColorModifier->getModifiedColor(maBlack));
+
+        BColor aExpectedRed(0.0, 0.426, 0.426);
+        CPPUNIT_ASSERT_EQUAL(aExpectedRed, 
aBColorModifier->getModifiedColor(maRed));
+        BColor aExpectedGreen(1.0, 0.43, 1.0);
+        CPPUNIT_ASSERT_EQUAL(aExpectedGreen, 
aBColorModifier->getModifiedColor(maGreen));
+        BColor aExpectedBlue(0.144, 0.144, 0);
+        CPPUNIT_ASSERT_EQUAL(aExpectedBlue, 
aBColorModifier->getModifiedColor(maBlue));
+        BColor aExpectedYellow(0.856, 0.856, 1.0);
+        CPPUNIT_ASSERT_EQUAL(aExpectedYellow, 
aBColorModifier->getModifiedColor(maYellow));
+        BColor aExpectedMagenta(0.0, 0.57, 0.0);
+        CPPUNIT_ASSERT_EQUAL(aExpectedMagenta, 
aBColorModifier->getModifiedColor(maMagenta));
+        BColor aExpectedCyan(1.0, 0.574, 0.574);
+        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_hueRotate>(basegfx::deg2rad(180.0));
+        CPPUNIT_ASSERT(aBColorModifier->operator==(*aBColorModifier2));
+    }
+
     CPPUNIT_TEST_SUITE(bcolormodifier);
     CPPUNIT_TEST(testGray);
     CPPUNIT_TEST(testInvert);
@@ -244,6 +276,7 @@ public:
     CPPUNIT_TEST(testStack);
     CPPUNIT_TEST(testSaturate);
     CPPUNIT_TEST(testLuminanceToAlpha);
+    CPPUNIT_TEST(testHueRotate);
     CPPUNIT_TEST_SUITE_END();
 };
 
diff --git a/include/basegfx/color/bcolormodifier.hxx 
b/include/basegfx/color/bcolormodifier.hxx
index c8fe3a2a88b4..5a3ca0a78adf 100644
--- a/include/basegfx/color/bcolormodifier.hxx
+++ b/include/basegfx/color/bcolormodifier.hxx
@@ -236,6 +236,31 @@ namespace basegfx
         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.
+
+        See:
+        https://www.w3.org/TR/filter-effects/#elementdef-fecolormatrix
+    */
+    class SAL_WARN_UNUSED BASEGFX_DLLPUBLIC BColorModifier_hueRotate final : 
public BColorModifier
+    {
+    private:
+        basegfx::B3DHomMatrix       maHueMatrix;
+
+    public:
+        BColorModifier_hueRotate(double fRad);
+
+        virtual ~BColorModifier_hueRotate() 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;
+    };
+
     /** convert color to black and white
 
         returns black when the luminance of the given color is less than
diff --git a/svgio/inc/svgfecolormatrixnode.hxx 
b/svgio/inc/svgfecolormatrixnode.hxx
index 631da8877372..a63d44715457 100644
--- a/svgio/inc/svgfecolormatrixnode.hxx
+++ b/svgio/inc/svgfecolormatrixnode.hxx
@@ -28,6 +28,7 @@ namespace svgio::svgreader
 enum class ColorType
 {
     None,
+    HueRotate,
     Saturate,
     LuminanceToAlpha
 };
@@ -36,7 +37,7 @@ class SvgFeColorMatrixNode final : public SvgNode
 {
 private:
     ColorType maType;
-    SvgNumber maValues;
+    OUString maValuesContent;
 
 public:
     SvgFeColorMatrixNode(SvgDocument& rDocument, SvgNode* pParent);
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 87c99ba72509..87beb7742405 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -165,8 +165,8 @@ CPPUNIT_TEST_FIXTURE(Test, testFeColorMatrix)
 
     //assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor", 
"modifier", "matrix");
     assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[1]", 
"modifier", "saturate");
-    //assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor", 
"modifier", "hueRotate");
-    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[2]", 
"modifier", "luminance_to_alpha");
+    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[2]", 
"modifier", "hueRotate");
+    assertXPath(pDocument, "/primitive2D/transform/mask/modifiedColor[3]", 
"modifier", "luminance_to_alpha");
 }
 
 CPPUNIT_TEST_FIXTURE(Test, testFilterFeGaussianBlur)
diff --git a/svgio/source/svgreader/svgfecolormatrixnode.cxx 
b/svgio/source/svgreader/svgfecolormatrixnode.cxx
index 2a02ddc3c0bd..42611e48efdd 100644
--- a/svgio/source/svgreader/svgfecolormatrixnode.cxx
+++ b/svgio/source/svgreader/svgfecolormatrixnode.cxx
@@ -26,7 +26,6 @@ namespace svgio::svgreader
 SvgFeColorMatrixNode::SvgFeColorMatrixNode(SvgDocument& rDocument, SvgNode* 
pParent)
     : SvgNode(SVGToken::FeColorMatrix, rDocument, pParent)
     , maType(ColorType::None)
-    , maValues(1.0)
 {
 }
 
@@ -50,17 +49,16 @@ void SvgFeColorMatrixNode::parseAttribute(const OUString& 
/*rTokenName*/, SVGTok
                 {
                     maType = ColorType::Saturate;
                 }
+                else if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), 
u"hueRotate"))
+                {
+                    maType = ColorType::HueRotate;
+                }
             }
             break;
         }
         case SVGToken::Values:
         {
-            SvgNumber aNum;
-
-            if (readSingleNumber(aContent, aNum))
-            {
-                maValues = aNum;
-            }
+            maValuesContent = aContent;
             break;
         }
         default:
@@ -82,10 +80,23 @@ void 
SvgFeColorMatrixNode::apply(drawinglayer::primitive2d::Primitive2DContainer
     }
     else if (maType == ColorType::Saturate)
     {
+        SvgNumber aNum(1.0);
+        readSingleNumber(maValuesContent, aNum);
+
         const drawinglayer::primitive2d::Primitive2DReference xRef(
             new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
                 std::move(rTarget),
-                
std::make_shared<basegfx::BColorModifier_saturate>(maValues.getNumber())));
+                
std::make_shared<basegfx::BColorModifier_saturate>(aNum.getNumber())));
+        rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef };
+    }
+    else if (maType == ColorType::HueRotate)
+    {
+        SvgNumber aNum(0.0);
+        readSingleNumber(maValuesContent, aNum);
+        const drawinglayer::primitive2d::Primitive2DReference xRef(
+            new drawinglayer::primitive2d::ModifiedColorPrimitive2D(
+                std::move(rTarget), 
std::make_shared<basegfx::BColorModifier_hueRotate>(
+                                        basegfx::deg2rad(aNum.getNumber()))));
         rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef };
     }
 }

Reply via email to