diff options
author | Xisco Fauli <xiscofauli@libreoffice.org> | 2023-06-27 23:21:25 +0200 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2023-06-28 10:05:50 +0200 |
commit | 0a18f318a13d4a9b81f717498d3a02ee274542de (patch) | |
tree | 0fc30eb87a501d7c991d0394e6187c0350555a6d /svgio | |
parent | c706fde1c4ecc6974bcf32ce33aacf3093355ae1 (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.mk | 1 | ||||
-rw-r--r-- | svgio/inc/svgfefloodnode.hxx | 49 | ||||
-rw-r--r-- | svgio/inc/svgtoken.hxx | 3 | ||||
-rw-r--r-- | svgio/qa/cppunit/SvgImportTest.cxx | 18 | ||||
-rw-r--r-- | svgio/qa/cppunit/data/filterFeFlood.svg | 16 | ||||
-rw-r--r-- | svgio/source/svgreader/svgdocumenthandler.cxx | 11 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfefloodnode.cxx | 162 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfilternode.cxx | 6 | ||||
-rw-r--r-- | svgio/source/svgreader/svgstyleattributes.cxx | 3 | ||||
-rw-r--r-- | svgio/source/svgreader/svgtoken.cxx | 5 | ||||
-rw-r--r-- | svgio/source/svgreader/svgusenode.cxx | 57 |
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(); |