svgio/inc/svgfilternode.hxx                      |    9 +++
 svgio/inc/svgtoken.hxx                           |    1 
 svgio/qa/cppunit/SvgImportTest.cxx               |   47 ++++++++++++++++++++
 svgio/qa/cppunit/data/inFilterAttribute.svg      |   13 +++++
 svgio/qa/cppunit/data/resultFilterAttribute.svg  |   13 +++++
 svgio/source/svgreader/svgfecolormatrixnode.cxx  |    3 +
 svgio/source/svgreader/svgfedropshadownode.cxx   |    3 +
 svgio/source/svgreader/svgfefloodnode.cxx        |    3 +
 svgio/source/svgreader/svgfegaussianblurnode.cxx |    3 +
 svgio/source/svgreader/svgfeimagenode.cxx        |    3 +
 svgio/source/svgreader/svgfeoffsetnode.cxx       |    3 +
 svgio/source/svgreader/svgfilternode.cxx         |   52 +++++++++++++++++++++++
 svgio/source/svgreader/svgtoken.cxx              |    1 
 13 files changed, 154 insertions(+)

New commits:
commit c73f3491bedafef884196c761d8f3d89f4dcff75
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Wed Feb 28 13:10:04 2024 +0100
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Thu Feb 29 17:52:05 2024 +0100

    tdf#159947: Add support for in and result filter attributes
    
    Change-Id: I8bc7e319a64c528893de8454c64545146ad4e9d8
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164108
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/svgio/inc/svgfilternode.hxx b/svgio/inc/svgfilternode.hxx
index 0c87ba54b47b..c3aa068bd3eb 100644
--- a/svgio/inc/svgfilternode.hxx
+++ b/svgio/inc/svgfilternode.hxx
@@ -27,11 +27,20 @@ namespace svgio::svgreader
 {
 class SvgFilterNode : public SvgNode
 {
+private:
+    OUString maIn;
+    OUString maResult;
+
 public:
     SvgFilterNode(SVGToken aType, SvgDocument& rDocument, SvgNode* pParent);
     virtual ~SvgFilterNode() override;
 
+    virtual void parseAttribute(SVGToken aSVGToken, const OUString& aContent) 
override;
+
     virtual void apply(drawinglayer::primitive2d::Primitive2DContainer& 
rTarget) const;
+
+    const OUString& getIn() const { return maIn; }
+    const OUString& getResult() const { return maResult; }
 };
 
 } // end of namespace svgio::svgreader
diff --git a/svgio/inc/svgtoken.hxx b/svgio/inc/svgtoken.hxx
index 3927a27d1db5..8ad390f0b4a5 100644
--- a/svgio/inc/svgtoken.hxx
+++ b/svgio/inc/svgtoken.hxx
@@ -42,6 +42,7 @@ namespace svgio::svgreader
             Version,
             Id,
             In,
+            Result,
             Rx,
             Ry,
             Points,
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 9eb8b37d70ca..99541f0b63b7 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -212,6 +212,53 @@ CPPUNIT_TEST_FIXTURE(Test, testFilterFeGaussianBlur)
     assertXPath(pDocument, "/primitive2D/transform/softedge"_ostr, 
"radius"_ostr, "5");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testInFilterAttribute)
+{
+    Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/inFilterAttribute.svg");
+    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
+
+    drawinglayer::Primitive2dXmlDump dumper;
+    xmlDocUniquePtr pDocument = dumper.dumpAndParse(aSequence);
+
+    CPPUNIT_ASSERT (pDocument);
+
+    // Without the fix in place, the feGaussianBlur and feColorMatrix filter 
would have been applied
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy11"_ostr, "1");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy12"_ostr, "0");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy13"_ostr, "40");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy21"_ostr, "0");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy22"_ostr, "1");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy23"_ostr, "40");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy31"_ostr, "0");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy32"_ostr, "0");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy33"_ostr, "1");
+    assertXPath(pDocument, 
"/primitive2D/transform/transform/polypolygoncolor"_ostr, "color"_ostr, 
"#ffffff");
+}
+
+CPPUNIT_TEST_FIXTURE(Test, testResultFilterAttribute)
+{
+    Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/resultFilterAttribute.svg");
+    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
+
+    drawinglayer::Primitive2dXmlDump dumper;
+    xmlDocUniquePtr pDocument = dumper.dumpAndParse(aSequence);
+
+    CPPUNIT_ASSERT (pDocument);
+
+    // Without the fix in place, the feColorMatrix filter would have been 
applied
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy11"_ostr, "1");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy12"_ostr, "0");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy13"_ostr, "40");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy21"_ostr, "0");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy22"_ostr, "1");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy23"_ostr, "40");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy31"_ostr, "0");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy32"_ostr, "0");
+    assertXPath(pDocument, "/primitive2D/transform/transform"_ostr, 
"xy33"_ostr, "1");
+    assertXPath(pDocument, "/primitive2D/transform/transform/softedge"_ostr, 
"radius"_ostr, "2");
+    assertXPath(pDocument, 
"/primitive2D/transform/transform/softedge/polypolygoncolor"_ostr, 
"color"_ostr, "#ffffff");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testFilterFeOffset)
 {
     Primitive2DSequence aSequenceTdf132246 = 
parseSvg(u"/svgio/qa/cppunit/data/filterFeOffset.svg");
diff --git a/svgio/qa/cppunit/data/inFilterAttribute.svg 
b/svgio/qa/cppunit/data/inFilterAttribute.svg
new file mode 100644
index 000000000000..f6e17e46e4cc
--- /dev/null
+++ b/svgio/qa/cppunit/data/inFilterAttribute.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; version="1.1" viewBox="0 0 500 500">
+  <defs>
+    <filter height="100" id="f1" width="100">
+      <feGaussianBlur stdDeviation="2.0"/>
+      <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0.4 0"/>
+      <feOffset dx="40" dy="40" in="SourceGraphic"/>
+    </filter>
+  </defs>
+  <g>
+    <rect fill="#FFFFFF" filter="url(#f1)" height="70" style="stroke: #A80036; 
stroke-width: 1.0;" width="10" x="10" y="10"/>
+  </g>
+</svg>
diff --git a/svgio/qa/cppunit/data/resultFilterAttribute.svg 
b/svgio/qa/cppunit/data/resultFilterAttribute.svg
new file mode 100644
index 000000000000..8d46731095e1
--- /dev/null
+++ b/svgio/qa/cppunit/data/resultFilterAttribute.svg
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<svg xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink"; version="1.1" viewBox="0 0 500 500">
+  <defs>
+    <filter height="100" id="f1" width="100">
+      <feGaussianBlur stdDeviation="2.0" result="output"/>
+      <feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0.4 0"/>
+      <feOffset dx="40" dy="40" in="output"/>
+    </filter>
+  </defs>
+  <g>
+    <rect fill="#FFFFFF" filter="url(#f1)" height="70" style="stroke: #A80036; 
stroke-width: 1.0;" width="10" x="10" y="10"/>
+  </g>
+</svg>
diff --git a/svgio/source/svgreader/svgfecolormatrixnode.cxx 
b/svgio/source/svgreader/svgfecolormatrixnode.cxx
index 3a7943ac4e4e..da42fa72f899 100644
--- a/svgio/source/svgreader/svgfecolormatrixnode.cxx
+++ b/svgio/source/svgreader/svgfecolormatrixnode.cxx
@@ -33,6 +33,9 @@ SvgFeColorMatrixNode::~SvgFeColorMatrixNode() {}
 
 void SvgFeColorMatrixNode::parseAttribute(SVGToken aSVGToken, const OUString& 
aContent)
 {
+    // call parent
+    SvgFilterNode::parseAttribute(aSVGToken, aContent);
+
     // parse own
     switch (aSVGToken)
     {
diff --git a/svgio/source/svgreader/svgfedropshadownode.cxx 
b/svgio/source/svgreader/svgfedropshadownode.cxx
index 2abe6c71c560..d5c67e162af1 100644
--- a/svgio/source/svgreader/svgfedropshadownode.cxx
+++ b/svgio/source/svgreader/svgfedropshadownode.cxx
@@ -40,6 +40,9 @@ SvgFeDropShadowNode::~SvgFeDropShadowNode() {}
 
 void SvgFeDropShadowNode::parseAttribute(SVGToken aSVGToken, const OUString& 
aContent)
 {
+    // call parent
+    SvgFilterNode::parseAttribute(aSVGToken, aContent);
+
     // parse own
     switch (aSVGToken)
     {
diff --git a/svgio/source/svgreader/svgfefloodnode.cxx 
b/svgio/source/svgreader/svgfefloodnode.cxx
index 775bdb3b1cb9..4c4efe9bf4c9 100644
--- a/svgio/source/svgreader/svgfefloodnode.cxx
+++ b/svgio/source/svgreader/svgfefloodnode.cxx
@@ -41,6 +41,9 @@ SvgFeFloodNode::~SvgFeFloodNode() {}
 
 void SvgFeFloodNode::parseAttribute(SVGToken aSVGToken, const OUString& 
aContent)
 {
+    // call parent
+    SvgFilterNode::parseAttribute(aSVGToken, aContent);
+
     // parse own
     switch (aSVGToken)
     {
diff --git a/svgio/source/svgreader/svgfegaussianblurnode.cxx 
b/svgio/source/svgreader/svgfegaussianblurnode.cxx
index 53b1513d255c..8c6d26681a2a 100644
--- a/svgio/source/svgreader/svgfegaussianblurnode.cxx
+++ b/svgio/source/svgreader/svgfegaussianblurnode.cxx
@@ -33,6 +33,9 @@ SvgFeGaussianBlurNode::~SvgFeGaussianBlurNode() {}
 
 void SvgFeGaussianBlurNode::parseAttribute(SVGToken aSVGToken, const OUString& 
aContent)
 {
+    // call parent
+    SvgFilterNode::parseAttribute(aSVGToken, aContent);
+
     // parse own
     switch (aSVGToken)
     {
diff --git a/svgio/source/svgreader/svgfeimagenode.cxx 
b/svgio/source/svgreader/svgfeimagenode.cxx
index 7174bcaf4a27..777f1fd48f22 100644
--- a/svgio/source/svgreader/svgfeimagenode.cxx
+++ b/svgio/source/svgreader/svgfeimagenode.cxx
@@ -38,6 +38,9 @@ SvgFeImageNode::~SvgFeImageNode() {}
 
 void SvgFeImageNode::parseAttribute(SVGToken aSVGToken, const OUString& 
aContent)
 {
+    // call parent
+    SvgFilterNode::parseAttribute(aSVGToken, aContent);
+
     // parse own
     switch (aSVGToken)
     {
diff --git a/svgio/source/svgreader/svgfeoffsetnode.cxx 
b/svgio/source/svgreader/svgfeoffsetnode.cxx
index 324920cde112..fd85b22a3116 100644
--- a/svgio/source/svgreader/svgfeoffsetnode.cxx
+++ b/svgio/source/svgreader/svgfeoffsetnode.cxx
@@ -34,6 +34,9 @@ SvgFeOffsetNode::~SvgFeOffsetNode() {}
 
 void SvgFeOffsetNode::parseAttribute(SVGToken aSVGToken, const OUString& 
aContent)
 {
+    // call parent
+    SvgFilterNode::parseAttribute(aSVGToken, aContent);
+
     // parse own
     switch (aSVGToken)
     {
diff --git a/svgio/source/svgreader/svgfilternode.cxx 
b/svgio/source/svgreader/svgfilternode.cxx
index 3e21e9c2adac..1d7198b7d466 100644
--- a/svgio/source/svgreader/svgfilternode.cxx
+++ b/svgio/source/svgreader/svgfilternode.cxx
@@ -17,6 +17,7 @@
  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
  */
 
+#include <unordered_map>
 #include <svgfilternode.hxx>
 #include <svgfecolormatrixnode.hxx>
 #include <svgfedropshadownode.hxx>
@@ -25,6 +26,9 @@
 #include <svgfegaussianblurnode.hxx>
 #include <svgfeoffsetnode.hxx>
 
+typedef std::unordered_map<OUString, const 
drawinglayer::primitive2d::Primitive2DContainer*>
+    IdGraphicSourceMapper;
+
 namespace svgio::svgreader
 {
 SvgFilterNode::SvgFilterNode(SVGToken aType, SvgDocument& rDocument, SvgNode* 
pParent)
@@ -34,6 +38,30 @@ SvgFilterNode::SvgFilterNode(SVGToken aType, SvgDocument& 
rDocument, SvgNode* pP
 
 SvgFilterNode::~SvgFilterNode() {}
 
+void SvgFilterNode::parseAttribute(SVGToken aSVGToken, const OUString& 
aContent)
+{
+    // call parent
+    SvgNode::parseAttribute(aSVGToken, aContent);
+
+    switch (aSVGToken)
+    {
+        case SVGToken::In:
+        {
+            maIn = aContent.trim();
+            break;
+        }
+        case SVGToken::Result:
+        {
+            maResult = aContent.trim();
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
 void SvgFilterNode::apply(drawinglayer::primitive2d::Primitive2DContainer& 
rTarget) const
 {
     if (rTarget.empty())
@@ -42,12 +70,36 @@ void 
SvgFilterNode::apply(drawinglayer::primitive2d::Primitive2DContainer& rTarg
     const auto& rChildren = getChildren();
     const sal_uInt32 nCount(rChildren.size());
 
+    IdGraphicSourceMapper aIdGraphicSourceMapperList;
+    drawinglayer::primitive2d::Primitive2DContainer aNewTarget = rTarget;
+    aIdGraphicSourceMapperList.emplace("SourceGraphic", &aNewTarget);
+    //TODO: Add SourceAlpha, BackgroundImage, BackgroundAlpha, FillPaint, 
StrokePaint ??
+
     // apply children's filters
     for (sal_uInt32 a(0); a < nCount; a++)
     {
         SvgFilterNode* pFilterNode = 
dynamic_cast<SvgFilterNode*>(rChildren[a].get());
         if (pFilterNode)
+        {
+            if (!pFilterNode->getIn().isEmpty())
+            {
+                const IdGraphicSourceMapper::const_iterator aResult(
+                    aIdGraphicSourceMapperList.find(pFilterNode->getIn()));
+
+                if (aResult != aIdGraphicSourceMapperList.end())
+                {
+                    rTarget = *aResult->second;
+                }
+            }
+
             pFilterNode->apply(rTarget);
+
+            if (!pFilterNode->getResult().isEmpty())
+            {
+                aNewTarget = rTarget;
+                aIdGraphicSourceMapperList.emplace(pFilterNode->getResult(), 
&aNewTarget);
+            }
+        }
     }
 }
 
diff --git a/svgio/source/svgreader/svgtoken.cxx 
b/svgio/source/svgreader/svgtoken.cxx
index fa28c8647cea..14c27a396631 100644
--- a/svgio/source/svgreader/svgtoken.cxx
+++ b/svgio/source/svgreader/svgtoken.cxx
@@ -41,6 +41,7 @@ constexpr auto aSVGTokenMap = 
frozen::make_unordered_map<std::u16string_view, SV
     { u"version", SVGToken::Version },
     { u"id", SVGToken::Id },
     { u"in", SVGToken::In },
+    { u"result", SVGToken::Result },
     { u"rx", SVGToken::Rx },
     { u"ry", SVGToken::Ry },
     { u"points", SVGToken::Points },

Reply via email to