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(-)

New commits:
commit fcd2db0dff13ac592573c53c7da5fa6844695514
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Wed Oct 2 13:07:47 2024 +0200
Commit:     Adolfo Jayme Barrientos <fit...@ubuntu.com>
CommitDate: Sat Oct 5 20:03:52 2024 +0200

    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 <xiscofa...@libreoffice.org>
    Tested-by: Jenkins
    Signed-off-by: Xisco Fauli <xiscofa...@libreoffice.org>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/174384
    Reviewed-by: Adolfo Jayme Barrientos <fit...@ubuntu.com>

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;
             }
 

Reply via email to