summaryrefslogtreecommitdiff
path: root/svgio
diff options
context:
space:
mode:
authorXisco Fauli <xiscofauli@libreoffice.org>2023-06-27 23:21:25 +0200
committerXisco Fauli <xiscofauli@libreoffice.org>2023-06-28 10:05:50 +0200
commit0a18f318a13d4a9b81f717498d3a02ee274542de (patch)
tree0fc30eb87a501d7c991d0394e6187c0350555a6d /svgio
parentc706fde1c4ecc6974bcf32ce33aacf3093355ae1 (diff)
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 <xiscofauli@libreoffice.org>
Diffstat (limited to 'svgio')
-rw-r--r--svgio/Library_svgio.mk1
-rw-r--r--svgio/inc/svgfefloodnode.hxx49
-rw-r--r--svgio/inc/svgtoken.hxx3
-rw-r--r--svgio/qa/cppunit/SvgImportTest.cxx18
-rw-r--r--svgio/qa/cppunit/data/filterFeFlood.svg16
-rw-r--r--svgio/source/svgreader/svgdocumenthandler.cxx11
-rw-r--r--svgio/source/svgreader/svgfefloodnode.cxx162
-rw-r--r--svgio/source/svgreader/svgfilternode.cxx6
-rw-r--r--svgio/source/svgreader/svgstyleattributes.cxx3
-rw-r--r--svgio/source/svgreader/svgtoken.cxx5
-rw-r--r--svgio/source/svgreader/svgusenode.cxx57
11 files changed, 298 insertions, 33 deletions
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();