svgio/Library_svgio.mk                        |    1 
 svgio/inc/svgfefloodnode.hxx                  |   49 +++++++
 svgio/inc/svgtoken.hxx                        |    3 
 svgio/qa/cppunit/SvgImportTest.cxx            |   18 ++
 svgio/qa/cppunit/data/filterFeFlood.svg       |   16 ++
 svgio/source/svgreader/svgdocumenthandler.cxx |   11 +
 svgio/source/svgreader/svgfefloodnode.cxx     |  162 ++++++++++++++++++++++++++
 svgio/source/svgreader/svgfilternode.cxx      |    6 
 svgio/source/svgreader/svgstyleattributes.cxx |    3 
 svgio/source/svgreader/svgtoken.cxx           |    5 
 svgio/source/svgreader/svgusenode.cxx         |   57 ++++-----
 11 files changed, 298 insertions(+), 33 deletions(-)

New commits:
commit 0a18f318a13d4a9b81f717498d3a02ee274542de
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Tue Jun 27 23:21:25 2023 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Wed Jun 28 10:05:50 2023 +0200

    tdf#156066: Add support for feFlood filter
    
    Change-Id: I4d01d40edd6fb91555fd734fc8378df1cbd5743a
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/153684
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/svgio/Library_svgio.mk b/svgio/Library_svgio.mk
index 3702806a311c..20797e339a81 100644
--- a/svgio/Library_svgio.mk
+++ b/svgio/Library_svgio.mk
@@ -61,6 +61,7 @@ $(eval $(call gb_Library_add_exception_objects,svgio,\
     svgio/source/svgreader/svggnode \
     svgio/source/svgreader/svganode \
     svgio/source/svgreader/svgfecolormatrixnode \
+    svgio/source/svgreader/svgfefloodnode \
     svgio/source/svgreader/svgfegaussianblurnode \
     svgio/source/svgreader/svgfeoffsetnode \
     svgio/source/svgreader/svgfilternode \
diff --git a/svgio/inc/svgfefloodnode.hxx b/svgio/inc/svgfefloodnode.hxx
new file mode 100644
index 000000000000..a8cb2da47e51
--- /dev/null
+++ b/svgio/inc/svgfefloodnode.hxx
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#pragma once
+
+#include "svgnode.hxx"
+#include "svgstyleattributes.hxx"
+
+namespace svgio::svgreader
+{
+class SvgFeFloodNode final : public SvgNode
+{
+private:
+    SvgNumber maX;
+    SvgNumber maY;
+    SvgNumber maWidth;
+    SvgNumber maHeight;
+    SvgPaint maFloodColor;
+    SvgNumber maFloodOpacity;
+
+public:
+    SvgFeFloodNode(SvgDocument& rDocument, SvgNode* pParent);
+    virtual ~SvgFeFloodNode() override;
+
+    virtual void parseAttribute(const OUString& rTokenName, SVGToken aSVGToken,
+                                const OUString& aContent) override;
+
+    void apply(drawinglayer::primitive2d::Primitive2DContainer& rTarget) const;
+};
+
+} // end of namespace svgio::svgreader
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/inc/svgtoken.hxx b/svgio/inc/svgtoken.hxx
index fb2e04c278f4..239cda0eb4cc 100644
--- a/svgio/inc/svgtoken.hxx
+++ b/svgio/inc/svgtoken.hxx
@@ -81,9 +81,12 @@ namespace svgio::svgreader
             ClipPathNode,
             ClipPathProperty,
             FeColorMatrix,
+            FeFlood,
             FeGaussianBlur,
             FeOffset,
             Filter,
+            FloodColor,
+            FloodOpacity,
             Mask,
             ClipPathUnits,
             MaskUnits,
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 7e32e83faf3a..9383b7ac5430 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -203,6 +203,24 @@ CPPUNIT_TEST_FIXTURE(Test, testFilterFeOffset)
     assertXPath(pDocument, "/primitive2D/transform/mask/transform", "xy33", 
"1");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testFilterFeFlood)
+{
+    Primitive2DSequence aSequenceTdf132246 = 
parseSvg(u"/svgio/qa/cppunit/data/filterFeFlood.svg");
+    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequenceTdf132246.getLength()));
+
+    drawinglayer::Primitive2dXmlDump dumper;
+    xmlDocUniquePtr pDocument = dumper.dumpAndParse(aSequenceTdf132246);
+
+    CPPUNIT_ASSERT (pDocument);
+
+    assertXPath(pDocument, "/primitive2D/transform/unifiedtransparence", 
"transparence", "50");
+    assertXPath(pDocument, 
"/primitive2D/transform/unifiedtransparence/polypolygoncolor", "color", 
"#008000");
+    assertXPath(pDocument, 
"/primitive2D/transform/unifiedtransparence/polypolygoncolor/polypolygon", 
"height", "100");
+    assertXPath(pDocument, 
"/primitive2D/transform/unifiedtransparence/polypolygoncolor/polypolygon", 
"width", "100");
+    assertXPath(pDocument, 
"/primitive2D/transform/unifiedtransparence/polypolygoncolor/polypolygon", 
"minx", "50");
+    assertXPath(pDocument, 
"/primitive2D/transform/unifiedtransparence/polypolygoncolor/polypolygon", 
"miny", "50");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf87309)
 {
     Primitive2DSequence aSequenceTdf87309 = 
parseSvg(u"/svgio/qa/cppunit/data/tdf87309.svg");
diff --git a/svgio/qa/cppunit/data/filterFeFlood.svg 
b/svgio/qa/cppunit/data/filterFeFlood.svg
new file mode 100644
index 000000000000..2c438ad1a9bf
--- /dev/null
+++ b/svgio/qa/cppunit/data/filterFeFlood.svg
@@ -0,0 +1,16 @@
+<svg xmlns="http://www.w3.org/2000/svg"; width="200" height="200">
+  <defs>
+    <filter id="floodFilter" filterUnits="userSpaceOnUse">
+      <feFlood
+        x="50"
+        y="50"
+        width="100"
+        height="100"
+        flood-color="green"
+        flood-opacity="0.5" />
+    </filter>
+  </defs>
+
+  <use filter="url(#floodFilter)" />
+</svg>
+
diff --git a/svgio/source/svgreader/svgdocumenthandler.cxx 
b/svgio/source/svgreader/svgdocumenthandler.cxx
index 397a7fed74a1..7883383c5287 100644
--- a/svgio/source/svgreader/svgdocumenthandler.cxx
+++ b/svgio/source/svgreader/svgdocumenthandler.cxx
@@ -41,8 +41,9 @@
 #include <svgstylenode.hxx>
 #include <svgimagenode.hxx>
 #include <svgclippathnode.hxx>
-#include <svgfegaussianblurnode.hxx>
 #include <svgfecolormatrixnode.hxx>
+#include <svgfefloodnode.hxx>
+#include <svgfegaussianblurnode.hxx>
 #include <svgfeoffsetnode.hxx>
 #include <svgfilternode.hxx>
 #include <svgmasknode.hxx>
@@ -340,6 +341,13 @@ namespace
                     mpTarget->parseAttributes(xAttribs);
                     break;
                 }
+                case SVGToken::FeFlood:
+                {
+                    /// new node for feFlood
+                    mpTarget = new SvgFeFloodNode(maDocument, mpTarget);
+                    mpTarget->parseAttributes(xAttribs);
+                    break;
+                }
                 case SVGToken::FeGaussianBlur:
                 {
                     /// new node for feGaussianBlur
@@ -461,6 +469,7 @@ namespace
 
                 /// structural elements for filters
                 case SVGToken::FeColorMatrix:
+                case SVGToken::FeFlood:
                 case SVGToken::FeGaussianBlur:
                 case SVGToken::FeOffset:
                 case SVGToken::Filter:
diff --git a/svgio/source/svgreader/svgfefloodnode.cxx 
b/svgio/source/svgreader/svgfefloodnode.cxx
new file mode 100644
index 000000000000..3cd1c178f2d4
--- /dev/null
+++ b/svgio/source/svgreader/svgfefloodnode.cxx
@@ -0,0 +1,162 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This file is part of the LibreOffice project.
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * This file incorporates work covered by the following license notice:
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements. See the NOTICE file distributed
+ *   with this work for additional information regarding copyright
+ *   ownership. The ASF licenses this file to you under the Apache
+ *   License, Version 2.0 (the "License"); you may not use this file
+ *   except in compliance with the License. You may obtain a copy of
+ *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
+ */
+
+#include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
+#include <drawinglayer/primitive2d/transformprimitive2d.hxx>
+#include <drawinglayer/primitive2d/unifiedtransparenceprimitive2d.hxx>
+#include <basegfx/polygon/b2dpolygontools.hxx>
+#include <svgfefloodnode.hxx>
+#include <o3tl/string_view.hxx>
+
+namespace svgio::svgreader
+{
+SvgFeFloodNode::SvgFeFloodNode(SvgDocument& rDocument, SvgNode* pParent)
+    : SvgNode(SVGToken::FeFlood, rDocument, pParent)
+    , maX(0.0)
+    , maY(0.0)
+    , maWidth(0.0)
+    , maHeight(0.0)
+    , maFloodColor(SvgPaint())
+    , maFloodOpacity(1.0)
+{
+}
+
+SvgFeFloodNode::~SvgFeFloodNode() {}
+
+void SvgFeFloodNode::parseAttribute(const OUString& /*rTokenName*/, SVGToken 
aSVGToken,
+                                    const OUString& aContent)
+{
+    // parse own
+    switch (aSVGToken)
+    {
+        case SVGToken::Style:
+        {
+            readLocalCssStyle(aContent);
+            break;
+        }
+        case SVGToken::X:
+        {
+            SvgNumber aNum;
+
+            if (readSingleNumber(aContent, aNum))
+            {
+                maX = aNum;
+            }
+            break;
+        }
+        case SVGToken::Y:
+        {
+            SvgNumber aNum;
+
+            if (readSingleNumber(aContent, aNum))
+            {
+                maY = aNum;
+            }
+            break;
+        }
+        case SVGToken::Width:
+        {
+            SvgNumber aNum;
+
+            if (readSingleNumber(aContent, aNum))
+            {
+                if (aNum.isPositive())
+                {
+                    maWidth = aNum;
+                }
+            }
+            break;
+        }
+        case SVGToken::Height:
+        {
+            SvgNumber aNum;
+
+            if (readSingleNumber(aContent, aNum))
+            {
+                if (aNum.isPositive())
+                {
+                    maHeight = aNum;
+                }
+            }
+            break;
+        }
+        case SVGToken::FloodColor:
+        {
+            SvgPaint aSvgPaint;
+            OUString aURL;
+            SvgNumber aOpacity;
+
+            if (readSvgPaint(aContent, aSvgPaint, aURL, aOpacity))
+            {
+                maFloodColor = aSvgPaint;
+            }
+            break;
+        }
+        case SVGToken::FloodOpacity:
+        {
+            SvgNumber aNum;
+
+            if (readSingleNumber(aContent, aNum))
+            {
+                maFloodOpacity = SvgNumber(std::clamp(aNum.getNumber(), 0.0, 
1.0), aNum.getUnit(),
+                                           aNum.isSet());
+            }
+            break;
+        }
+
+        default:
+        {
+            break;
+        }
+    }
+}
+
+void SvgFeFloodNode::apply(drawinglayer::primitive2d::Primitive2DContainer& 
rTarget) const
+{
+    const double fWidth(maWidth.solve(*this, NumberType::xcoordinate));
+    const double fHeight(maHeight.solve(*this, NumberType::ycoordinate));
+
+    if (fWidth <= 0.0 || fHeight <= 0.0)
+        return;
+
+    const double fX(maX.solve(*this, NumberType::xcoordinate));
+    const double fY(maY.solve(*this, NumberType::ycoordinate));
+    const basegfx::B2DRange aRange(fX, fY, fX + fWidth, fY + fHeight);
+
+    basegfx::B2DPolyPolygon 
aPolygon(basegfx::utils::createPolygonFromRect(aRange));
+    drawinglayer::primitive2d::Primitive2DReference xRef(
+        new drawinglayer::primitive2d::PolyPolygonColorPrimitive2D(aPolygon,
+                                                                   
maFloodColor.getBColor()));
+
+    rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef };
+
+    const double fOpacity(maFloodOpacity.solve(*this));
+
+    if (basegfx::fTools::less(fOpacity, 1.0))
+    {
+        xRef = new 
drawinglayer::primitive2d::UnifiedTransparencePrimitive2D(std::move(rTarget),
+                                                                             
1.0 - fOpacity);
+
+        rTarget = drawinglayer::primitive2d::Primitive2DContainer{ xRef };
+    }
+}
+
+} // end of namespace svgio::svgreader
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgfilternode.cxx 
b/svgio/source/svgreader/svgfilternode.cxx
index f95cf3530701..6ff71f002e73 100644
--- a/svgio/source/svgreader/svgfilternode.cxx
+++ b/svgio/source/svgreader/svgfilternode.cxx
@@ -19,6 +19,7 @@
 
 #include <svgfilternode.hxx>
 #include <svgfecolormatrixnode.hxx>
+#include <svgfefloodnode.hxx>
 #include <svgfegaussianblurnode.hxx>
 #include <svgfeoffsetnode.hxx>
 
@@ -61,6 +62,11 @@ void 
SvgFilterNode::apply(drawinglayer::primitive2d::Primitive2DContainer& rTarg
                 = dynamic_cast<const SvgFeOffsetNode&>(*pCandidate);
             rFeOffsetNode.apply(rTarget);
         }
+        else if (pCandidate->getType() == SVGToken::FeFlood)
+        {
+            const SvgFeFloodNode& rFeFloodNode = dynamic_cast<const 
SvgFeFloodNode&>(*pCandidate);
+            rFeFloodNode.apply(rTarget);
+        }
     }
 }
 
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx 
b/svgio/source/svgreader/svgstyleattributes.cxx
index 66b8f60848f4..eb7ab2f290c6 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -1166,9 +1166,6 @@ namespace svgio::svgreader
             const std::optional<basegfx::B2DHomMatrix>& pTransform,
             bool bIsPrimitive) const
         {
-            if(rSource.empty())
-                return;
-
             const double fOpacity(getOpacity().solve(mrOwner));
 
             if(basegfx::fTools::equalZero(fOpacity))
diff --git a/svgio/source/svgreader/svgtoken.cxx 
b/svgio/source/svgreader/svgtoken.cxx
index 83271638b99d..7a49896b0ed1 100644
--- a/svgio/source/svgreader/svgtoken.cxx
+++ b/svgio/source/svgreader/svgtoken.cxx
@@ -28,7 +28,7 @@ namespace svgio::svgreader
 constexpr const std::u16string_view constToken_Title = u"title";
 constexpr const std::u16string_view constToken_Desc = u"desc";
 
-constexpr frozen::unordered_map<std::u16string_view, SVGToken, 140> 
aSVGTokenMapperList
+constexpr frozen::unordered_map<std::u16string_view, SVGToken, 143> 
aSVGTokenMapperList
 {
     { u"width", SVGToken::Width },
     { u"height", SVGToken::Height },
@@ -81,9 +81,12 @@ constexpr frozen::unordered_map<std::u16string_view, 
SVGToken, 140> aSVGTokenMap
     { u"clipPath", SVGToken::ClipPathNode },
     { u"clip-path", SVGToken::ClipPathProperty },
     { u"feColorMatrix", SVGToken::FeColorMatrix },
+    { u"feFlood", SVGToken::FeFlood },
     { u"feGaussianBlur", SVGToken::FeGaussianBlur },
     { u"feOffset", SVGToken::FeOffset },
     { u"filter", SVGToken::Filter },
+    { u"flood-color", SVGToken::FloodColor },
+    { u"flood-opacity", SVGToken::FloodOpacity },
     { u"mask", SVGToken::Mask },
     { u"clipPathUnits", SVGToken::ClipPathUnits },
     { u"maskUnits", SVGToken::MaskUnits },
diff --git a/svgio/source/svgreader/svgusenode.cxx 
b/svgio/source/svgreader/svgusenode.cxx
index 0d385576ac88..b0fed16c73eb 100644
--- a/svgio/source/svgreader/svgusenode.cxx
+++ b/svgio/source/svgreader/svgusenode.cxx
@@ -128,39 +128,40 @@ namespace svgio::svgreader
 
         void 
SvgUseNode::decomposeSvgNode(drawinglayer::primitive2d::Primitive2DContainer& 
rTarget, bool /*bReferenced*/) const
         {
-            // try to access link to content
-            const SvgNode* pXLink = getDocument().findSvgNodeById(maXLink);
-
-            if (!pXLink || Display::None == pXLink->getDisplay() || 
mbDecomposingSvgNode)
-                return;
-
-            // decompose children
             drawinglayer::primitive2d::Primitive2DContainer aNewTarget;
-
-            // todo: in case mpXLink is a SVGToken::Svg or SVGToken::Symbol the
-            // SVG docs want the getWidth() and getHeight() from this node
-            // to be valid for the subtree.
-            mbDecomposingSvgNode = true;
-            const_cast< SvgNode* >(pXLink)->setAlternativeParent(this);
-            pXLink->decomposeSvgNode(aNewTarget, true);
-            const_cast< SvgNode* >(pXLink)->setAlternativeParent();
-            mbDecomposingSvgNode = false;
-
-            if(aNewTarget.empty())
-                return;
-
             basegfx::B2DHomMatrix aTransform;
 
-            if(getX().isSet() || getY().isSet())
-            {
-                aTransform.translate(
-                    getX().solve(*this, NumberType::xcoordinate),
-                    getY().solve(*this, NumberType::ycoordinate));
-            }
+            // try to access link to content
+            const SvgNode* pXLink = getDocument().findSvgNodeById(maXLink);
 
-            if(getTransform())
+            if (pXLink)
             {
-                aTransform = *getTransform() * aTransform;
+                if (Display::None == pXLink->getDisplay() || 
mbDecomposingSvgNode)
+                    return;
+
+                // todo: in case mpXLink is a SVGToken::Svg or 
SVGToken::Symbol the
+                // SVG docs want the getWidth() and getHeight() from this node
+                // to be valid for the subtree.
+                mbDecomposingSvgNode = true;
+                const_cast< SvgNode* >(pXLink)->setAlternativeParent(this);
+                pXLink->decomposeSvgNode(aNewTarget, true);
+                const_cast< SvgNode* >(pXLink)->setAlternativeParent();
+                mbDecomposingSvgNode = false;
+
+                if(aNewTarget.empty())
+                    return;
+
+                if(getX().isSet() || getY().isSet())
+                {
+                    aTransform.translate(
+                        getX().solve(*this, NumberType::xcoordinate),
+                        getY().solve(*this, NumberType::ycoordinate));
+                }
+
+                if(getTransform())
+                {
+                    aTransform = *getTransform() * aTransform;
+                }
             }
 
             const SvgStyleAttributes* pStyle = getSvgStyleAttributes();

Reply via email to