diff options
author | Xisco Fauli <xiscofauli@libreoffice.org> | 2024-10-02 13:07:47 +0200 |
---|---|---|
committer | Adolfo Jayme Barrientos <fitojb@ubuntu.com> | 2024-10-05 20:03:52 +0200 |
commit | fcd2db0dff13ac592573c53c7da5fa6844695514 (patch) | |
tree | 39dda15ce926cd9319942537a9b358a397bb997b /svgio | |
parent | 9f4571da1df09461a58a7a7d1a7f0efcb7ac4959 (diff) |
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 <xiscofauli@libreoffice.org>
Tested-by: Jenkins
Signed-off-by: Xisco Fauli <xiscofauli@libreoffice.org>
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174384
Reviewed-by: Adolfo Jayme Barrientos <fitojb@ubuntu.com>
Diffstat (limited to 'svgio')
-rw-r--r-- | svgio/inc/svgmarkernode.hxx | 4 | ||||
-rw-r--r-- | svgio/inc/svgstyleattributes.hxx | 15 | ||||
-rw-r--r-- | svgio/qa/cppunit/SvgImportTest.cxx | 11 | ||||
-rw-r--r-- | svgio/qa/cppunit/data/contextStrokeGradient.svg | 24 | ||||
-rw-r--r-- | svgio/source/svgreader/svgmarkernode.cxx | 3 | ||||
-rw-r--r-- | svgio/source/svgreader/svgstyleattributes.cxx | 169 |
6 files changed, 144 insertions, 82 deletions
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 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"> + <style> + path { + fill: none; + stroke-width: 4px; + marker: url(#diamond); + } + </style> + <defs> + <linearGradient + id="swatch7"> + <stop + style="stop-color:#23a2b0;stop-opacity:1;" + offset="0" + id="stop7" /> + </linearGradient> + </defs> + + <path d="M 10,50 v -20 h 40 v -20" stroke="url(#swatch7)"/> + + <marker id="diamond" markerWidth="12" markerHeight="12" refX="6" refY="6" markerUnits="userSpaceOnUse"> + <circle cx="6" cy="6" r="3" fill="white" stroke="context-stroke" stroke-width="2"/> + </marker> +</svg> 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<const SvgMarkerNode *>(&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<SvgStyleAttributes*>(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<SvgStyleAttributes*>(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<SvgMarkerNode&>(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; } |