drawinglayer/source/tools/primitive2dxmldump.cxx |   13 +++
 svgio/Library_svgio.mk                           |    1 
 svgio/inc/svgfegaussianblurnode.hxx              |   59 +++++++++++++++
 svgio/inc/svgfilternode.hxx                      |    2 
 svgio/inc/svgtoken.hxx                           |    3 
 svgio/qa/cppunit/SvgImportTest.cxx               |   21 ++++-
 svgio/qa/cppunit/data/filterFeGaussianBlur.svg   |   11 ++
 svgio/source/svgreader/svgdocumenthandler.cxx    |   11 ++
 svgio/source/svgreader/svgfegaussianblurnode.cxx |   86 +++++++++++++++++++++++
 svgio/source/svgreader/svgfilternode.cxx         |   22 +++++
 svgio/source/svgreader/svgstyleattributes.cxx    |    6 +
 svgio/source/svgreader/svgtoken.cxx              |    6 +
 12 files changed, 235 insertions(+), 6 deletions(-)

New commits:
commit 77354ba8695f66331bfc6cc3f5e3f2e9d15f1740
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Tue Jun 6 19:04:50 2023 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Wed Jun 7 14:49:42 2023 +0200

    tdf#132246: add basic support for feGaussianBlur
    
    for now only apply it if in="SourceGraphic" is explicitly
    used
    
    Change-Id: I3daea354f61ba5f6b3d13da1e7a71e99d51f6729
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/152684
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/drawinglayer/source/tools/primitive2dxmldump.cxx 
b/drawinglayer/source/tools/primitive2dxmldump.cxx
index 2267a1080c13..7edb5bce5c89 100644
--- a/drawinglayer/source/tools/primitive2dxmldump.cxx
+++ b/drawinglayer/source/tools/primitive2dxmldump.cxx
@@ -28,6 +28,7 @@
 #include <drawinglayer/primitive2d/PolyPolygonStrokePrimitive2D.hxx>
 #include <drawinglayer/primitive2d/PolyPolygonColorPrimitive2D.hxx>
 #include <drawinglayer/primitive2d/hiddengeometryprimitive2d.hxx>
+#include <drawinglayer/primitive2d/softedgeprimitive2d.hxx>
 #include <drawinglayer/primitive2d/textdecoratedprimitive2d.hxx>
 #include <primitive2d/textlineprimitive2d.hxx>
 #include <drawinglayer/primitive2d/textprimitive2d.hxx>
@@ -1134,6 +1135,18 @@ void Primitive2dXmlDump::decomposeAndWrite(
                 rWriter.endElement();
                 break;
             }
+            case PRIMITIVE2D_ID_SOFTEDGEPRIMITIVE2D:
+            {
+                // SoftEdgePrimitive2D.
+                const SoftEdgePrimitive2D& rSoftEdgePrimitive2D
+                    = dynamic_cast<const 
SoftEdgePrimitive2D&>(*pBasePrimitive);
+                rWriter.startElement("softedge");
+                rWriter.attribute("radius", 
OUString::number(rSoftEdgePrimitive2D.getRadius()));
+
+                decomposeAndWrite(rSoftEdgePrimitive2D.getChildren(), rWriter);
+                rWriter.endElement();
+                break;
+            }
 
             case PRIMITIVE2D_ID_SCENEPRIMITIVE2D:
             {
diff --git a/svgio/Library_svgio.mk b/svgio/Library_svgio.mk
index 8770f733d441..247653732d6f 100644
--- a/svgio/Library_svgio.mk
+++ b/svgio/Library_svgio.mk
@@ -57,6 +57,7 @@ $(eval $(call gb_Library_add_exception_objects,svgio,\
     svgio/source/svgreader/svgellipsenode \
     svgio/source/svgreader/svggnode \
     svgio/source/svgreader/svganode \
+    svgio/source/svgreader/svgfegaussianblurnode \
     svgio/source/svgreader/svgfilternode \
     svgio/source/svgreader/svggradientnode \
     svgio/source/svgreader/svggradientstopnode \
diff --git a/svgio/inc/svgfegaussianblurnode.hxx 
b/svgio/inc/svgfegaussianblurnode.hxx
new file mode 100644
index 000000000000..5dec4463198f
--- /dev/null
+++ b/svgio/inc/svgfegaussianblurnode.hxx
@@ -0,0 +1,59 @@
+/* -*- 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"
+#include <basegfx/matrix/b2dhommatrix.hxx>
+
+namespace svgio::svgreader
+{
+/*
+FIXME: If no value is provided and this is the first filter primitive,
+then this filter primitive will use SourceGraphic as its input.
+If no value is provided and this is a subsequent filter primitive,
+then this filter primitive will use the result from the previous
+filter primitive as its input.
+*/
+enum class In
+{
+    None,
+    SourceGraphic
+};
+
+class SvgFeGaussianBlurNode final : public SvgNode
+{
+private:
+    SvgNumber maStdDeviation;
+    In maIn;
+
+public:
+    SvgFeGaussianBlurNode(SvgDocument& rDocument, SvgNode* pParent);
+    virtual ~SvgFeGaussianBlurNode() 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/svgfilternode.hxx b/svgio/inc/svgfilternode.hxx
index e6c24450b4e2..19ce2cb34b33 100644
--- a/svgio/inc/svgfilternode.hxx
+++ b/svgio/inc/svgfilternode.hxx
@@ -30,6 +30,8 @@ class SvgFilterNode final : public SvgNode
 public:
     SvgFilterNode(SvgDocument& rDocument, SvgNode* pParent);
     virtual ~SvgFilterNode() override;
+
+    void apply(drawinglayer::primitive2d::Primitive2DContainer& rTarget) const;
 };
 
 } // end of namespace svgio::svgreader
diff --git a/svgio/inc/svgtoken.hxx b/svgio/inc/svgtoken.hxx
index 73c083a620e6..262b5f3dda55 100644
--- a/svgio/inc/svgtoken.hxx
+++ b/svgio/inc/svgtoken.hxx
@@ -41,6 +41,7 @@ namespace svgio::svgreader
             Xmlns,
             Version,
             Id,
+            In,
             Rx,
             Ry,
             Points,
@@ -69,6 +70,7 @@ namespace svgio::svgreader
             StartOffset,
             Method,
             Spacing,
+            StdDeviation,
             TextAlign,
             PathLength,
             Type,
@@ -78,6 +80,7 @@ namespace svgio::svgreader
             Color,
             ClipPathNode,
             ClipPathProperty,
+            FeGaussianBlur,
             Filter,
             Mask,
             ClipPathUnits,
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index 6e4ac0255677..967bcc0275cf 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -24,9 +24,6 @@
 #include <memory>
 #include <string_view>
 
-namespace
-{
-
 using namespace css;
 using namespace css::uno;
 using namespace css::io;
@@ -82,6 +79,8 @@ void Test::checkRectPrimitive(Primitive2DSequence const & 
rPrimitive)
 
 }
 
+namespace
+{
 bool arePrimitive2DSequencesEqual(const Primitive2DSequence& rA, const 
Primitive2DSequence& rB)
 {
     return std::equal(rA.begin(), rA.end(), rB.begin(), rB.end(),
@@ -91,6 +90,7 @@ bool arePrimitive2DSequencesEqual(const Primitive2DSequence& 
rA, const Primitive
             return drawinglayer::primitive2d::arePrimitive2DReferencesEqual(a, 
b);
         });
 }
+}
 
 // Attributes for an object (like rect as in this case) can be defined
 // in different ways (directly with xml attributes, or with CSS styles),
@@ -135,6 +135,19 @@ CPPUNIT_TEST_FIXTURE(Test, testSymbol)
     assertXPath(pDocument, "/primitive2D/transform/polypolygoncolor", "color", 
"#00d000");
 }
 
+CPPUNIT_TEST_FIXTURE(Test, testFilterFeGaussianBlur)
+{
+    Primitive2DSequence aSequenceTdf132246 = 
parseSvg(u"/svgio/qa/cppunit/data/filterFeGaussianBlur.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/softedge", "radius", "5");
+}
+
 CPPUNIT_TEST_FIXTURE(Test, testTdf87309)
 {
     Primitive2DSequence aSequenceTdf87309 = 
parseSvg(u"/svgio/qa/cppunit/data/tdf87309.svg");
@@ -1055,8 +1068,6 @@ CPPUNIT_TEST_FIXTURE(Test, testTspanFillOpacity)
     CPPUNIT_ASSERT_EQUAL(static_cast<sal_Int32>(70), nTransparence);
 }
 
-}
-
 CPPUNIT_PLUGIN_IMPLEMENT();
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/qa/cppunit/data/filterFeGaussianBlur.svg 
b/svgio/qa/cppunit/data/filterFeGaussianBlur.svg
new file mode 100644
index 000000000000..e8fd73068a0b
--- /dev/null
+++ b/svgio/qa/cppunit/data/filterFeGaussianBlur.svg
@@ -0,0 +1,11 @@
+<svg
+  width="230"
+  height="120"
+  xmlns="http://www.w3.org/2000/svg";
+  xmlns:xlink="http://www.w3.org/1999/xlink";>
+  <filter id="blurMe">
+    <feGaussianBlur  in="SourceGraphic" stdDeviation="5"/>
+  </filter>
+  <circle cx="170" cy="60" r="50" fill="green" filter="url(#blurMe)" />
+</svg>
+
diff --git a/svgio/source/svgreader/svgdocumenthandler.cxx 
b/svgio/source/svgreader/svgdocumenthandler.cxx
index ac866b37f0d2..5e61693e64c7 100644
--- a/svgio/source/svgreader/svgdocumenthandler.cxx
+++ b/svgio/source/svgreader/svgdocumenthandler.cxx
@@ -41,6 +41,7 @@
 #include <svgstylenode.hxx>
 #include <svgimagenode.hxx>
 #include <svgclippathnode.hxx>
+#include <svgfegaussianblurnode.hxx>
 #include <svgfilternode.hxx>
 #include <svgmasknode.hxx>
 #include <svgmarkernode.hxx>
@@ -341,6 +342,13 @@ namespace
                     mpTarget->parseAttributes(xAttribs);
                     break;
                 }
+                case SVGToken::FeGaussianBlur:
+                {
+                    /// new node for feGaussianBlur
+                    mpTarget = new SvgFeGaussianBlurNode(maDocument, mpTarget);
+                    mpTarget->parseAttributes(xAttribs);
+                    break;
+                }
                 case SVGToken::Filter:
                 {
                     /// new node for Filter
@@ -442,8 +450,9 @@ namespace
                 /// styles (as stylesheets)
                 case SVGToken::Style:
 
-                /// structural elements clip-path, filter and mask
+                /// structural elements clip-path, feGaussianBlur, filter and 
mask
                 case SVGToken::ClipPathNode:
+                case SVGToken::FeGaussianBlur:
                 case SVGToken::Filter:
                 case SVGToken::Mask:
 
diff --git a/svgio/source/svgreader/svgfegaussianblurnode.cxx 
b/svgio/source/svgreader/svgfegaussianblurnode.cxx
new file mode 100644
index 000000000000..fff21345c4d8
--- /dev/null
+++ b/svgio/source/svgreader/svgfegaussianblurnode.cxx
@@ -0,0 +1,86 @@
+/* -*- 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 <svgfegaussianblurnode.hxx>
+#include <drawinglayer/primitive2d/softedgeprimitive2d.hxx>
+#include <o3tl/string_view.hxx>
+
+namespace svgio::svgreader
+{
+SvgFeGaussianBlurNode::SvgFeGaussianBlurNode(SvgDocument& rDocument, SvgNode* 
pParent)
+    : SvgNode(SVGToken::FeGaussianBlur, rDocument, pParent)
+    , maStdDeviation(SvgNumber(0.0))
+    , maIn(In::None)
+{
+}
+
+SvgFeGaussianBlurNode::~SvgFeGaussianBlurNode() {}
+
+void SvgFeGaussianBlurNode::parseAttribute(const OUString& /*rTokenName*/, 
SVGToken aSVGToken,
+                                           const OUString& aContent)
+{
+    // parse own
+    switch (aSVGToken)
+    {
+        case SVGToken::StdDeviation:
+        {
+            SvgNumber aNum;
+
+            if (readSingleNumber(aContent, aNum))
+            {
+                if (aNum.isPositive())
+                {
+                    maStdDeviation = aNum;
+                }
+            }
+            break;
+        }
+        case SVGToken::In:
+        {
+            if (!aContent.isEmpty())
+            {
+                if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), 
u"SourceGraphic"))
+                {
+                    maIn = In::SourceGraphic;
+                }
+            }
+            break;
+        }
+        default:
+        {
+            break;
+        }
+    }
+}
+
+void 
SvgFeGaussianBlurNode::apply(drawinglayer::primitive2d::Primitive2DContainer& 
rTarget) const
+{
+    if (maIn == In::SourceGraphic)
+    {
+        const drawinglayer::primitive2d::Primitive2DReference xRef(
+            new 
drawinglayer::primitive2d::SoftEdgePrimitive2D(maStdDeviation.getNumber(),
+                                                               
std::move(rTarget)));
+
+        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 374feb06247b..8eb0beb65e6b 100644
--- a/svgio/source/svgreader/svgfilternode.cxx
+++ b/svgio/source/svgreader/svgfilternode.cxx
@@ -18,6 +18,7 @@
  */
 
 #include <svgfilternode.hxx>
+#include <svgfegaussianblurnode.hxx>
 
 namespace svgio::svgreader
 {
@@ -28,6 +29,27 @@ SvgFilterNode::SvgFilterNode(SvgDocument& rDocument, 
SvgNode* pParent)
 
 SvgFilterNode::~SvgFilterNode() {}
 
+void SvgFilterNode::apply(drawinglayer::primitive2d::Primitive2DContainer& 
rTarget) const
+{
+    if (rTarget.empty())
+        return;
+
+    const auto& rChildren = getChildren();
+    const sal_uInt32 nCount(rChildren.size());
+
+    // apply children's filters
+    for (sal_uInt32 a(0); a < nCount; a++)
+    {
+        SvgNode* pCandidate = rChildren[a].get();
+        if (pCandidate->getType() == SVGToken::FeGaussianBlur)
+        {
+            const SvgFeGaussianBlurNode* pFeGaussianBlurNode
+                = dynamic_cast<const SvgFeGaussianBlurNode*>(pCandidate);
+            pFeGaussianBlurNode->apply(rTarget);
+        }
+    }
+}
+
 } // end of namespace svgio::svgreader
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx 
b/svgio/source/svgreader/svgstyleattributes.cxx
index 5a3c9396ae91..eda757af80d3 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -1208,6 +1208,12 @@ namespace svgio::svgreader
 
             if(!aSource.empty()) // test again, applied clipPath may have lead 
to empty geometry
             {
+                const SvgFilterNode* pFilter = accessFilterXLink();
+                if(pFilter)
+                {
+                    pFilter->apply(aSource);
+                }
+
                 const SvgMaskNode* pMask = accessMaskXLink();
                 if(pMask)
                 {
diff --git a/svgio/source/svgreader/svgtoken.cxx 
b/svgio/source/svgreader/svgtoken.cxx
index a472466b3995..48a0c8eb47df 100644
--- a/svgio/source/svgreader/svgtoken.cxx
+++ b/svgio/source/svgreader/svgtoken.cxx
@@ -34,6 +34,7 @@ namespace svgio::svgreader
         const char aSVGStrXmlns[] = "xmlns";
         const char aSVGStrVersion[] = "version";
         const char aSVGStrId[] = "id";
+        const char aSVGStrIn[] = "in";
         const char aSVGStrRx[] = "rx";
         const char aSVGStrRy[] = "ry";
         const char aSVGStrPoints[] = "points";
@@ -61,6 +62,7 @@ namespace svgio::svgreader
         const char aSVGStrStartOffset[] = "startOffset";
         const char aSVGStrMethod[] = "method";
         const char aSVGStrSpacing[] = "spacing";
+        const char aSVGStrStdDeviation[] = "stdDeviation";
         const char aSVGStrTextAlign[] = "text-align";
         const char aSVGStrPathLength[] = "pathLength";
         const char aSVGStrType[] = "type";
@@ -70,6 +72,7 @@ namespace svgio::svgreader
         const char aSVGStrColor[] = "color";
         const char aSVGStrClipPathNode[] = "clipPath";
         const char aSVGStrClipPathProperty[] = "clip-path";
+        const char aSVGStrFeGaussianBlur[] = "feGaussianBlur";
         const char aSVGStrFilter[] = "filter";
         const char aSVGStrMask[] = "mask";
         const char aSVGStrClipPathUnits[] = "clipPathUnits";
@@ -182,6 +185,7 @@ namespace svgio::svgreader
                 { aSVGStrXmlns, SVGToken::Xmlns },
                 { aSVGStrVersion, SVGToken::Version },
                 { aSVGStrId, SVGToken::Id },
+                { aSVGStrIn, SVGToken::In },
                 { aSVGStrRx, SVGToken::Rx },
                 { aSVGStrRy, SVGToken::Ry },
                 { aSVGStrPoints, SVGToken::Points },
@@ -209,6 +213,7 @@ namespace svgio::svgreader
                 { aSVGStrStartOffset, SVGToken::StartOffset },
                 { aSVGStrMethod, SVGToken::Method },
                 { aSVGStrSpacing, SVGToken::Spacing },
+                { aSVGStrStdDeviation, SVGToken::StdDeviation },
                 { aSVGStrTextAlign, SVGToken::TextAlign },
                 { aSVGStrPathLength, SVGToken::PathLength },
                 { aSVGStrType, SVGToken::Type },
@@ -218,6 +223,7 @@ namespace svgio::svgreader
                 { aSVGStrColor, SVGToken::Color },
                 { aSVGStrClipPathNode, SVGToken::ClipPathNode },
                 { aSVGStrClipPathProperty, SVGToken::ClipPathProperty },
+                { aSVGStrFeGaussianBlur, SVGToken::FeGaussianBlur },
                 { aSVGStrFilter, SVGToken::Filter },
                 { aSVGStrMask, SVGToken::Mask },
                 { aSVGStrClipPathUnits, SVGToken::ClipPathUnits },

Reply via email to