From fcd2db0dff13ac592573c53c7da5fa6844695514 Mon Sep 17 00:00:00 2001 From: Xisco Fauli Date: Wed, 2 Oct 2024 13:07:47 +0200 Subject: tdf#163212: context-fill/context-stroke can also use gradients Change-Id: Ic6f7f5e0817d8f5fccee64938004aa899bde47dc Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174382 Reviewed-by: Xisco Fauli Tested-by: Jenkins Signed-off-by: Xisco Fauli Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174384 Reviewed-by: Adolfo Jayme Barrientos --- svgio/inc/svgmarkernode.hxx | 4 + svgio/inc/svgstyleattributes.hxx | 15 ++- svgio/qa/cppunit/SvgImportTest.cxx | 11 ++ svgio/qa/cppunit/data/contextStrokeGradient.svg | 24 ++++ svgio/source/svgreader/svgmarkernode.cxx | 3 +- svgio/source/svgreader/svgstyleattributes.cxx | 169 +++++++++++++----------- 6 files changed, 144 insertions(+), 82 deletions(-) create mode 100644 svgio/qa/cppunit/data/contextStrokeGradient.svg (limited to 'svgio') diff --git a/svgio/inc/svgmarkernode.hxx b/svgio/inc/svgmarkernode.hxx index b8fa7c000e68..489387dc07e7 100644 --- a/svgio/inc/svgmarkernode.hxx +++ b/svgio/inc/svgmarkernode.hxx @@ -60,6 +60,8 @@ namespace svgio::svgreader double mfAngle; MarkerOrient maMarkerOrient; + const SvgStyleAttributes* maContextStyleAttibutes; + public: SvgMarkerNode( SvgDocument& rDocument, @@ -106,6 +108,8 @@ namespace svgio::svgreader MarkerOrient getMarkerOrient() const { return maMarkerOrient; } void setMarkerOrient(const MarkerOrient aMarkerOrient) { maMarkerOrient = aMarkerOrient; } + const SvgStyleAttributes* getContextStyleAttributes() const { return maContextStyleAttibutes; } + void setContextStyleAttributes(const SvgStyleAttributes* aContextStyleAttibutes) { maContextStyleAttibutes = aContextStyleAttibutes; } }; } // end of namespace svgio::svgreader diff --git a/svgio/inc/svgstyleattributes.hxx b/svgio/inc/svgstyleattributes.hxx index 30cbab965644..46b8baf4d1d3 100644 --- a/svgio/inc/svgstyleattributes.hxx +++ b/svgio/inc/svgstyleattributes.hxx @@ -248,18 +248,21 @@ namespace svgio::svgreader bool mbStrokeDasharraySet : 1; // tdf#155651 Defines if 'context-fill' is used in fill - bool mbContextFill : 1; + bool mbUseFillFromContextFill : 1; + + // tdf#155651 Defines if 'context-stroke' is used in fill + bool mbUseFillFromContextStroke : 1; + + // tdf#155651 Defines if 'context-fill' is used in stroke + bool mbUseStrokeFromContextFill : 1; // tdf#155651 Defines if 'context-stroke' is used in stroke - bool mbContextStroke : 1; + bool mbUseStrokeFromContextStroke : 1; // tdf#94765 Check id references in gradient/pattern getters OUString maNodeFillURL; OUString maNodeStrokeURL; - const basegfx::BColor* maContextFill; - const basegfx::BColor* maContextStroke; - /// internal helpers void add_fillGradient( const basegfx::B2DPolyPolygon& rPath, @@ -320,6 +323,8 @@ namespace svgio::svgreader void readCssStyle(std::u16string_view rCandidate); const SvgStyleAttributes* getParentStyle() const; + const SvgMarkerNode* getMarkerParentNode() const; + SvgStyleAttributes(SvgNode& rOwner); ~SvgStyleAttributes(); diff --git a/svgio/qa/cppunit/SvgImportTest.cxx b/svgio/qa/cppunit/SvgImportTest.cxx index 0f2478860d9b..9d03b0bae39d 100644 --- a/svgio/qa/cppunit/SvgImportTest.cxx +++ b/svgio/qa/cppunit/SvgImportTest.cxx @@ -686,6 +686,17 @@ CPPUNIT_TEST_FIXTURE(Test, testContextStroke) assertXPath(pDocument, "/primitive2D/transform/transform[4]/polypolygonstroke/line"_ostr, "color"_ostr, u"#ff0000"_ustr); } +CPPUNIT_TEST_FIXTURE(Test, testContextStrokeGradient) +{ + xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/contextStrokeGradient.svg"); + + assertXPath(pDocument, "/primitive2D/transform/svglineargradient"_ostr); + assertXPath(pDocument, "/primitive2D/transform/transform[1]/svglineargradient"_ostr); + assertXPath(pDocument, "/primitive2D/transform/transform[2]/svglineargradient"_ostr); + assertXPath(pDocument, "/primitive2D/transform/transform[3]/svglineargradient"_ostr); + assertXPath(pDocument, "/primitive2D/transform/transform[4]/svglineargradient"_ostr); +} + CPPUNIT_TEST_FIXTURE(Test, testMarkerInPresentation) { xmlDocUniquePtr pDocument = dumpAndParseSvg(u"/svgio/qa/cppunit/data/markerInPresentation.svg"); diff --git a/svgio/qa/cppunit/data/contextStrokeGradient.svg b/svgio/qa/cppunit/data/contextStrokeGradient.svg new file mode 100644 index 000000000000..7de3f70b6a0e --- /dev/null +++ b/svgio/qa/cppunit/data/contextStrokeGradient.svg @@ -0,0 +1,24 @@ + + + + + + + + + + + + + + diff --git a/svgio/source/svgreader/svgmarkernode.cxx b/svgio/source/svgreader/svgmarkernode.cxx index 2279920634a6..c2e1f2716ab9 100644 --- a/svgio/source/svgreader/svgmarkernode.cxx +++ b/svgio/source/svgreader/svgmarkernode.cxx @@ -33,7 +33,8 @@ namespace svgio::svgreader maMarkerWidth(3), maMarkerHeight(3), mfAngle(0.0), - maMarkerOrient(MarkerOrient::notset) + maMarkerOrient(MarkerOrient::notset), + maContextStyleAttibutes(nullptr) { } diff --git a/svgio/source/svgreader/svgstyleattributes.cxx b/svgio/source/svgreader/svgstyleattributes.cxx index 5fe78f8b58d0..c3dbdaacea47 100644 --- a/svgio/source/svgreader/svgstyleattributes.cxx +++ b/svgio/source/svgreader/svgstyleattributes.cxx @@ -259,6 +259,23 @@ namespace svgio::svgreader return nullptr; } + const SvgMarkerNode* SvgStyleAttributes::getMarkerParentNode() const + { + if (SVGToken::Marker == mrOwner.getType()) + return static_cast(&mrOwner); + + const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); + if (pSvgStyleAttributes && maResolvingParent[32] < nStyleDepthLimit) + { + ++maResolvingParent[32]; + const SvgMarkerNode* ret = pSvgStyleAttributes->getMarkerParentNode(); + --maResolvingParent[32]; + return ret; + } + + return nullptr; + } + void SvgStyleAttributes::add_text( drawinglayer::primitive2d::Primitive2DContainer& rTarget, drawinglayer::primitive2d::Primitive2DContainer&& rSource) const @@ -600,9 +617,36 @@ namespace svgio::svgreader drawinglayer::primitive2d::Primitive2DContainer& rTarget, const basegfx::B2DRange& rGeoRange) const { - const basegfx::BColor* pFill = getFill(); - const SvgGradientNode* pFillGradient = getSvgGradientNodeFill(); - const SvgPatternNode* pFillPattern = getSvgPatternNodeFill(); + const basegfx::BColor* pFill = nullptr; + const SvgGradientNode* pFillGradient = nullptr; + const SvgPatternNode* pFillPattern = nullptr; + + if (mbUseFillFromContextFill) + { + if (const SvgMarkerNode* pMarker = getMarkerParentNode()) + { + const SvgStyleAttributes* pStyle = pMarker->getContextStyleAttributes(); + pFill = pStyle->getFill(); + pFillGradient = pStyle->getSvgGradientNodeFill(); + pFillPattern = pStyle->getSvgPatternNodeFill(); + } + } + else if (mbUseFillFromContextStroke) + { + if (const SvgMarkerNode* pMarker = getMarkerParentNode()) + { + const SvgStyleAttributes* pStyle = pMarker->getContextStyleAttributes(); + pFill = pStyle->getStroke(); + pFillGradient = pStyle->getSvgGradientNodeStroke(); + pFillPattern = pStyle->getSvgPatternNodeStroke(); + } + } + else + { + pFill = getFill(); + pFillGradient = getSvgGradientNodeFill(); + pFillPattern = getSvgPatternNodeFill(); + } if(!(pFill || pFillGradient || pFillPattern)) return; @@ -656,9 +700,36 @@ namespace svgio::svgreader drawinglayer::primitive2d::Primitive2DContainer& rTarget, const basegfx::B2DRange& rGeoRange) const { - const basegfx::BColor* pStroke = getStroke(); - const SvgGradientNode* pStrokeGradient = getSvgGradientNodeStroke(); - const SvgPatternNode* pStrokePattern = getSvgPatternNodeStroke(); + const basegfx::BColor* pStroke = nullptr; + const SvgGradientNode* pStrokeGradient = nullptr; + const SvgPatternNode* pStrokePattern = nullptr; + + if(mbUseStrokeFromContextFill) + { + if (const SvgMarkerNode* pMarker = getMarkerParentNode()) + { + const SvgStyleAttributes* pStyle = pMarker->getContextStyleAttributes(); + pStroke = pStyle->getFill(); + pStrokeGradient = pStyle->getSvgGradientNodeFill(); + pStrokePattern = pStyle->getSvgPatternNodeFill(); + } + } + else if(mbUseStrokeFromContextStroke) + { + if (const SvgMarkerNode* pMarker = getMarkerParentNode()) + { + const SvgStyleAttributes* pStyle = pMarker->getContextStyleAttributes(); + pStroke = pStyle->getStroke(); + pStrokeGradient = pStyle->getSvgGradientNodeStroke(); + pStrokePattern = pStyle->getSvgPatternNodeStroke(); + } + } + else + { + pStroke = getStroke(); + pStrokeGradient = getSvgGradientNodeStroke(); + pStrokePattern = getSvgPatternNodeStroke(); + } if(!(pStroke || pStrokeGradient || pStrokePattern)) return; @@ -823,15 +894,11 @@ namespace svgio::svgreader rMarkerTransform.identity(); rClipRange.reset(); - // Set the current fill to the marker before calling getMarkerPrimitives, - // which calls decomposeSvgNode to decompose the children of the marker. - // If any of the children uses 'fill="context-fill"', then it will use it - const_cast(rMarker.getSvgStyleAttributes())->maContextFill = getFill(); - - // Set the current stroke to the marker before calling getMarkerPrimitives, + // Set the current style attibutes to the marker before calling getMarkerPrimitives, // which calls decomposeSvgNode to decompose the children of the marker. - // If any of the children uses 'stroke="context-stroke"', then it will use it - const_cast(rMarker.getSvgStyleAttributes())->maContextStroke = getStroke(); + // If any children uses 'context-fill' or 'context-stroke', + // then these style attributes will be used in add_fill or add_stroke + const_cast(rMarker).setContextStyleAttributes(this); // get marker primitive representation rMarkerPrimitives = rMarker.getMarkerPrimitives(); @@ -1320,12 +1387,12 @@ namespace svgio::svgreader maBaselineShift(BaselineShift::Baseline), maBaselineShiftNumber(0), maDominantBaseline(DominantBaseline::Auto), - maResolvingParent(35, 0), + maResolvingParent(34, 0), mbStrokeDasharraySet(false), - mbContextFill(false), - mbContextStroke(false), - maContextFill(nullptr), - maContextStroke(nullptr) + mbUseFillFromContextFill(false), + mbUseFillFromContextStroke(false), + mbUseStrokeFromContextFill(false), + mbUseStrokeFromContextStroke(false) { } @@ -1347,11 +1414,11 @@ namespace svgio::svgreader if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"context-fill")) { - mbContextFill = true; + mbUseFillFromContextFill = true; } else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"context-stroke")) { - mbContextStroke = true; + mbUseFillFromContextStroke = true; } else if(readSvgPaint(aContent, aSvgPaint, aURL, aOpacity)) { @@ -1400,11 +1467,11 @@ namespace svgio::svgreader if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"context-stroke")) { - mbContextStroke = true; + mbUseStrokeFromContextStroke = true; } else if(o3tl::equalsIgnoreAsciiCase(o3tl::trim(aContent), u"context-fill")) { - mbContextFill = true; + mbUseStrokeFromContextFill = true; } else if(readSvgPaint(aContent, aSvgPaint, aURL, aOpacity)) { @@ -2049,40 +2116,6 @@ namespace svgio::svgreader } } - const basegfx::BColor* SvgStyleAttributes::getContextFill() const - { - if (SVGToken::Marker == mrOwner.getType()) - return maContextFill; - - const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); - if (pSvgStyleAttributes && maResolvingParent[33] < nStyleDepthLimit) - { - ++maResolvingParent[33]; - auto ret = pSvgStyleAttributes->getContextFill(); - --maResolvingParent[33]; - return ret; - } - - return nullptr; - } - - const basegfx::BColor* SvgStyleAttributes::getContextStroke() const - { - if (SVGToken::Marker == mrOwner.getType()) - return maContextStroke; - - const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); - if (pSvgStyleAttributes && maResolvingParent[32] < nStyleDepthLimit) - { - ++maResolvingParent[32]; - auto ret = pSvgStyleAttributes->getContextStroke(); - --maResolvingParent[32]; - return ret; - } - - return nullptr; - } - bool SvgStyleAttributes::isClipPathContent() const { if (SVGToken::ClipPathNode == mrOwner.getType()) @@ -2151,14 +2184,6 @@ namespace svgio::svgreader } } } - else if (mbContextFill) - { - return getContextFill(); - } - else if (mbContextStroke) - { - return getContextStroke(); - } else if (maNodeFillURL.isEmpty()) { const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); @@ -2204,14 +2229,6 @@ namespace svgio::svgreader return &maStroke.getBColor(); } } - else if (mbContextFill) - { - return getContextFill(); - } - else if (mbContextStroke) - { - return getContextStroke(); - } else if (maNodeStrokeURL.isEmpty()) { const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); @@ -2430,11 +2447,11 @@ namespace svgio::svgreader const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle(); - if (pSvgStyleAttributes && maResolvingParent[34] < nStyleDepthLimit) + if (pSvgStyleAttributes && maResolvingParent[33] < nStyleDepthLimit) { - ++maResolvingParent[34]; + ++maResolvingParent[33]; auto ret = pSvgStyleAttributes->getOpacity(); - --maResolvingParent[34]; + --maResolvingParent[33]; return ret; } -- cgit