diff options
author | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-03-14 23:53:49 +0100 |
---|---|---|
committer | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-03-15 01:06:22 +0100 |
commit | b240f6198fae7221b7cd3e4678403ad99827b53d (patch) | |
tree | 4fe24d057f26b58ccc17af4355485ad8ae0518dd /svgio | |
parent | ad161bf882099553949469f99759493c38169c8a (diff) |
tdf#48062: Add support for xor, in and out operators in feComposite
atop and arithmetic are still missing
Change-Id: I9b5bfeaa87b48071708ca4cb082916ea5f260adb
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/164852
Tested-by: Jenkins
Reviewed-by: Xisco Fauli <xiscofauli@libreoffice.org>
Diffstat (limited to 'svgio')
-rw-r--r-- | svgio/inc/svgfecompositenode.hxx | 9 | ||||
-rw-r--r-- | svgio/inc/svgtoken.hxx | 1 | ||||
-rw-r--r-- | svgio/qa/cppunit/SvgImportTest.cxx | 28 | ||||
-rw-r--r-- | svgio/qa/cppunit/data/filterFeComposite.svg | 44 | ||||
-rw-r--r-- | svgio/source/svgreader/svgfecompositenode.cxx | 69 | ||||
-rw-r--r-- | svgio/source/svgreader/svgtoken.cxx | 1 |
6 files changed, 129 insertions, 23 deletions
diff --git a/svgio/inc/svgfecompositenode.hxx b/svgio/inc/svgfecompositenode.hxx index 44cef845c07f..2fa321cc6700 100644 --- a/svgio/inc/svgfecompositenode.hxx +++ b/svgio/inc/svgfecompositenode.hxx @@ -24,12 +24,21 @@ namespace svgio::svgreader { +enum class Operator +{ + Over, + In, + Out, + Xor, +}; + class SvgFeCompositeNode : public SvgFilterNode { private: OUString maIn; OUString maIn2; OUString maResult; + Operator maOperator; public: SvgFeCompositeNode(SvgDocument& rDocument, SvgNode* pParent); diff --git a/svgio/inc/svgtoken.hxx b/svgio/inc/svgtoken.hxx index aa2d2a74e6c3..203e7f0996c0 100644 --- a/svgio/inc/svgtoken.hxx +++ b/svgio/inc/svgtoken.hxx @@ -95,6 +95,7 @@ namespace svgio::svgreader Filter, FloodColor, FloodOpacity, + Operator, Mask, ClipPathUnits, MaskUnits, diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx index 1d875e2b74a7..dc933c9693dc 100644 --- a/svgio/qa/cppunit/SvgImportTest.cxx +++ b/svgio/qa/cppunit/SvgImportTest.cxx @@ -235,20 +235,20 @@ CPPUNIT_TEST_FIXTURE(Test, testFilterFeComposite) CPPUNIT_ASSERT (pDocument); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[1]"_ostr, "color"_ostr, "#ff0000"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[1]/polypolygon"_ostr, "height"_ostr, "100"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[1]/polypolygon"_ostr, "width"_ostr, "100"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[1]/polypolygon"_ostr, "minx"_ostr, "70"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[1]/polypolygon"_ostr, "miny"_ostr, "70"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[1]/polypolygon"_ostr, "maxx"_ostr, "170"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[1]/polypolygon"_ostr, "maxy"_ostr, "170"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[2]"_ostr, "color"_ostr, "#6ab150"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[2]/polypolygon"_ostr, "height"_ostr, "100"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[2]/polypolygon"_ostr, "width"_ostr, "100"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[2]/polypolygon"_ostr, "minx"_ostr, "30"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[2]/polypolygon"_ostr, "miny"_ostr, "30"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[2]/polypolygon"_ostr, "maxx"_ostr, "130"); - assertXPath(pDocument, "/primitive2D/transform/transform/polypolygoncolor[2]/polypolygon"_ostr, "maxy"_ostr, "130"); + assertXPath(pDocument, "/primitive2D/transform/mask"_ostr, 5); + // over operator + assertXPath(pDocument, "/primitive2D/transform/mask[1]/polypolygoncolor"_ostr, 3); + assertXPath(pDocument, "/primitive2D/transform/mask[1]/polypolygon/polygon/point"_ostr, 8); + // xor operator + assertXPath(pDocument, "/primitive2D/transform/mask[2]/polypolygoncolor"_ostr, 3); + assertXPath(pDocument, "/primitive2D/transform/mask[2]/polypolygon/polygon[1]/point"_ostr, 8); + assertXPath(pDocument, "/primitive2D/transform/mask[2]/polypolygon/polygon[2]/point"_ostr, 4); + // in operator + assertXPath(pDocument, "/primitive2D/transform/mask[3]/polypolygoncolor"_ostr, 3); + assertXPath(pDocument, "/primitive2D/transform/mask[3]/polypolygon/polygon/point"_ostr, 4); + // out operator + assertXPath(pDocument, "/primitive2D/transform/mask[4]/polypolygoncolor"_ostr, 3); + assertXPath(pDocument, "/primitive2D/transform/mask[4]/polypolygon/polygon/point"_ostr, 6); } CPPUNIT_TEST_FIXTURE(Test, testFilterFeGaussianBlur) diff --git a/svgio/qa/cppunit/data/filterFeComposite.svg b/svgio/qa/cppunit/data/filterFeComposite.svg index 0662eaa6f547..eea28d04647f 100644 --- a/svgio/qa/cppunit/data/filterFeComposite.svg +++ b/svgio/qa/cppunit/data/filterFeComposite.svg @@ -1,10 +1,44 @@ -<svg width="100" height="120" viewBox="0 0 200 240" xmlns="http://www.w3.org/2000/svg"> +<svg width="100%" height="100%" viewBox="0 0 150 150" xmlns="http://www.w3.org/2000/svg"> <defs> - <filter id="filter" filterUnits="userSpaceOnUse" x="0" y="0" width="100%" height="100%"> - <feFlood x="30" y="30" width="100" height="100" flood-color="#6ab150" flood-opacity="1" result="img1"></feFlood> - <feFlood x="70" y="70" width="100" height="100" flood-color="#ff0000" flood-opacity="1" result="img2"></feFlood> + <filter id="over" filterUnits="userSpaceOnUse"> + <feFlood x="3" y="3" width="10" height="10" flood-color="#6ab150" flood-opacity="1" result="img1"></feFlood> + <feFlood x="7" y="7" width="10" height="10" flood-color="#ff0000" flood-opacity="1" result="img2"></feFlood> <feComposite in="img1" in2="img2" operator="over"></feComposite> </filter> + <filter id="xor" filterUnits="userSpaceOnUse"> + <feFlood x="3" y="23" width="10" height="10" flood-color="#6ab150" flood-opacity="1" result="img1"></feFlood> + <feFlood x="7" y="27" width="10" height="10" flood-color="#ff0000" flood-opacity="1" result="img2"></feFlood> + <feComposite in="img1" in2="img2" operator="xor"></feComposite> + </filter> + <filter id="in" filterUnits="userSpaceOnUse"> + <feFlood x="3" y="43" width="10" height="10" flood-color="#6ab150" flood-opacity="1" result="img1"></feFlood> + <feFlood x="7" y="47" width="10" height="10" flood-color="#ff0000" flood-opacity="1" result="img2"></feFlood> + <feComposite in="img1" in2="img2" operator="in"></feComposite> + </filter> + <filter id="out" filterUnits="userSpaceOnUse"> + <feFlood x="3" y="63" width="10" height="10" flood-color="#6ab150" flood-opacity="1" result="img1"></feFlood> + <feFlood x="7" y="67" width="10" height="10" flood-color="#ff0000" flood-opacity="1" result="img2"></feFlood> + <feComposite in="img1" in2="img2" operator="out"></feComposite> + </filter> + <filter id="atop" filterUnits="userSpaceOnUse"> + <feFlood x="3" y="83" width="10" height="10" flood-color="#6ab150" flood-opacity="1" result="img1"></feFlood> + <feFlood x="7" y="87" width="10" height="10" flood-color="#ff0000" flood-opacity="1" result="img2"></feFlood> + <feComposite in="img1" in2="img2" operator="atop"></feComposite> + </filter> </defs> - <use style="filter: url(#filter)"></use> + + <use style="filter: url(#over)"></use> + <text x="20" y="10" dominant-baseline="middle" style="font-size:5px;">operator="over"</text> + + <use style="filter: url(#xor)"></use> + <text x="20" y="30" dominant-baseline="middle" style="font-size:5px;">operator="xor"</text> + + <use style="filter: url(#in)"></use> + <text x="20" y="50" dominant-baseline="middle" style="font-size:5px;">operator="in"</text> + + <use style="filter: url(#out)"></use> + <text x="20" y="70" dominant-baseline="middle" style="font-size:5px;">operator="out"</text> + + <use style="filter: url(#atop)"></use> + <text x="20" y="90" dominant-baseline="middle" style="font-size:5px;">operator="atop"</text> </svg> diff --git a/svgio/source/svgreader/svgfecompositenode.cxx b/svgio/source/svgreader/svgfecompositenode.cxx index b3418fca8709..95ec021969d8 100644 --- a/svgio/source/svgreader/svgfecompositenode.cxx +++ b/svgio/source/svgreader/svgfecompositenode.cxx @@ -18,11 +18,16 @@ #include <svgfecompositenode.hxx> #include <o3tl/string_view.hxx> +#include <basegfx/polygon/b2dpolygontools.hxx> +#include <basegfx/polygon/b2dpolypolygoncutter.hxx> +#include <basegfx/polygon/b2dpolypolygon.hxx> +#include <drawinglayer/primitive2d/maskprimitive2d.hxx> namespace svgio::svgreader { SvgFeCompositeNode::SvgFeCompositeNode(SvgDocument& rDocument, SvgNode* pParent) : SvgFilterNode(SVGToken::FeComposite, rDocument, pParent) + , maOperator(Operator::Over) { } @@ -53,6 +58,29 @@ void SvgFeCompositeNode::parseAttribute(SVGToken aSVGToken, const OUString& aCon maResult = aContent.trim(); break; } + case SVGToken::Operator: + { + if (!aContent.isEmpty()) + { + if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"over")) + { + maOperator = Operator::Over; + } + else if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"in")) + { + maOperator = Operator::In; + } + else if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"out")) + { + maOperator = Operator::Out; + } + else if (o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"xor")) + { + maOperator = Operator::Xor; + } + } + break; + } default: { break; @@ -63,18 +91,51 @@ void SvgFeCompositeNode::parseAttribute(SVGToken aSVGToken, const OUString& aCon void SvgFeCompositeNode::apply(drawinglayer::primitive2d::Primitive2DContainer& rTarget, const SvgFilterNode* pParent) const { - if (const drawinglayer::primitive2d::Primitive2DContainer* rSource2 + basegfx::B2DPolyPolygon aPolyPolygon, aPolyPolygon2; + + // Process maIn2 first + if (const drawinglayer::primitive2d::Primitive2DContainer* pSource2 = pParent->findGraphicSource(maIn2)) { - rTarget = *rSource2; + rTarget.append(*pSource2); + const basegfx::B2DRange aRange2( + pSource2->getB2DRange(drawinglayer::geometry::ViewInformation2D())); + + aPolyPolygon2 = basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aRange2)); } - if (const drawinglayer::primitive2d::Primitive2DContainer* rSource + if (const drawinglayer::primitive2d::Primitive2DContainer* pSource = pParent->findGraphicSource(maIn)) { - rTarget.append(*rSource); + rTarget.append(*pSource); + const basegfx::B2DRange aRange( + pSource->getB2DRange(drawinglayer::geometry::ViewInformation2D())); + + aPolyPolygon = basegfx::B2DPolyPolygon(basegfx::utils::createPolygonFromRect(aRange)); + } + + basegfx::B2DPolyPolygon aResult; + if (maOperator == Operator::Over) + { + aResult = basegfx::utils::solvePolygonOperationOr(aPolyPolygon, aPolyPolygon2); + } + else if (maOperator == Operator::Out) + { + aResult = basegfx::utils::solvePolygonOperationDiff(aPolyPolygon, aPolyPolygon2); + } + else if (maOperator == Operator::In) + { + aResult = basegfx::utils::solvePolygonOperationAnd(aPolyPolygon, aPolyPolygon2); + } + else if (maOperator == Operator::Xor) + { + aResult = basegfx::utils::solvePolygonOperationXor(aPolyPolygon, aPolyPolygon2); } + rTarget = drawinglayer::primitive2d::Primitive2DContainer{ + new drawinglayer::primitive2d::MaskPrimitive2D(std::move(aResult), std::move(rTarget)) + }; + pParent->addGraphicSourceToMapper(maResult, rTarget); } diff --git a/svgio/source/svgreader/svgtoken.cxx b/svgio/source/svgreader/svgtoken.cxx index 04b3f9fa3ec6..b6e22b63c547 100644 --- a/svgio/source/svgreader/svgtoken.cxx +++ b/svgio/source/svgreader/svgtoken.cxx @@ -93,6 +93,7 @@ constexpr auto aSVGTokenMap = frozen::make_unordered_map<std::u16string_view, SV { u"filter", SVGToken::Filter }, { u"flood-color", SVGToken::FloodColor }, { u"flood-opacity", SVGToken::FloodOpacity }, + { u"operator", SVGToken::Operator }, { u"mask", SVGToken::Mask }, { u"clipPathUnits", SVGToken::ClipPathUnits }, { u"maskUnits", SVGToken::MaskUnits }, |