diff options
author | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-02-28 13:10:04 +0100 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-02-29 17:52:05 +0100 |
commit | c73f3491bedafef884196c761d8f3d89f4dcff75 (patch) | |
tree | b717a9b94efa2180f82ef2c13e4a00b229b5dd34 /svgio | |
parent | 1245614991654b9d3ddb15f644a689585fd4c9de (diff) |
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 <xiscofauli@libreoffice.org>
Diffstat (limited to 'svgio')
-rw-r--r-- | svgio/inc/svgfilternode.hxx | 9 | ||||
-rw-r--r-- | svgio/inc/svgtoken.hxx | 1 | ||||
-rw-r--r-- | svgio/qa/cppunit/SvgImportTest.cxx | 47 | ||||
-rw-r--r-- | svgio/qa/cppunit/data/inFilterAttribute.svg | 13 | ||||
-rw-r--r-- | svgio/qa/cppunit/data/resultFilterAttribute.svg | 13 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfecolormatrixnode.cxx | 3 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfedropshadownode.cxx | 3 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfefloodnode.cxx | 3 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfegaussianblurnode.cxx | 3 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfeimagenode.cxx | 3 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfeoffsetnode.cxx | 3 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfilternode.cxx | 52 | ||||
-rw-r--r-- | svgio/source/svgreader/svgtoken.cxx | 1 |
13 files changed, 154 insertions, 0 deletions
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 }, |