svgio/inc/svgstyleattributes.hxx              |    3 +
 svgio/qa/cppunit/SvgImportTest.cxx            |   24 ++++++++++++++
 svgio/qa/cppunit/data/ClipRule.svg            |   18 ++++++++++
 svgio/source/svgreader/svgstyleattributes.cxx |   44 +++++++++++++++++++-------
 4 files changed, 78 insertions(+), 11 deletions(-)

New commits:
commit 4f61276dae10fdaf2ed33ab23d98adbe311cb7ee
Author:     Xisco Fauli <xiscofa...@libreoffice.org>
AuthorDate: Thu Jul 28 18:37:32 2022 +0200
Commit:     Xisco Fauli <xiscofa...@libreoffice.org>
CommitDate: Fri Jul 29 08:21:59 2022 +0200

    svgio: Add support for clip-rule="evenodd"
    
    Change-Id: I028aa88bdd72b4f87526a3d1edabd612d7686571
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137577
    Tested-by: Jenkins
    Reviewed-by: Xisco Fauli <xiscofa...@libreoffice.org>

diff --git a/svgio/inc/svgstyleattributes.hxx b/svgio/inc/svgstyleattributes.hxx
index 8489430b7546..529e91b75b8e 100644
--- a/svgio/inc/svgstyleattributes.hxx
+++ b/svgio/inc/svgstyleattributes.hxx
@@ -338,6 +338,9 @@ namespace svgio::svgreader
             /// fill rule content
             FillRule getFillRule() const;
 
+            /// clip rule content
+            FillRule getClipRule() const;
+
             /// fill StrokeDasharray content
             const SvgNumberVector& getStrokeDasharray() const;
 
diff --git a/svgio/qa/cppunit/SvgImportTest.cxx 
b/svgio/qa/cppunit/SvgImportTest.cxx
index f23556ee621c..8037f850768a 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -66,6 +66,7 @@ class Test : public test::BootstrapFixture, public 
XmlTestTools
     void testShapeWithClipPath();
     void testClipPathUsingClipPath();
     void testFillRule();
+    void testClipRule();
     void testi125329();
     void testMaskingPath07b();
     void test123926();
@@ -112,6 +113,7 @@ public:
     CPPUNIT_TEST(testShapeWithClipPath);
     CPPUNIT_TEST(testClipPathUsingClipPath);
     CPPUNIT_TEST(testFillRule);
+    CPPUNIT_TEST(testClipRule);
     CPPUNIT_TEST(testi125329);
     CPPUNIT_TEST(testMaskingPath07b);
     CPPUNIT_TEST(test123926);
@@ -719,6 +721,28 @@ void Test::testFillRule()
     assertXPath(pDocument, 
"/primitive2D/transform/polypolygonstroke/polypolygon/polygon", 2);
 }
 
+void Test::testClipRule()
+{
+    Primitive2DSequence aSequence = 
parseSvg(u"/svgio/qa/cppunit/data/ClipRule.svg");
+    CPPUNIT_ASSERT_EQUAL(1, static_cast<int>(aSequence.getLength()));
+
+    drawinglayer::Primitive2dXmlDump dumper;
+    xmlDocUniquePtr pDocument = 
dumper.dumpAndParse(Primitive2DContainer(aSequence));
+
+    CPPUNIT_ASSERT (pDocument);
+
+    // Without the place in place, this test would have failed with
+    // - Expected: 5
+    // - Actual  : 10
+    assertXPath(pDocument, 
"/primitive2D/transform/mask[1]/polypolygon/polygon/point", 5);
+    assertXPath(pDocument, "/primitive2D/transform/mask[1]/polypolygoncolor", 
"color", "#0000ff");
+    assertXPath(pDocument, 
"/primitive2D/transform/mask[1]/polypolygoncolor/polypolygon/polygon/point", 5);
+
+    assertXPath(pDocument, 
"/primitive2D/transform/mask[2]/polypolygon/polygon/point", 5);
+    assertXPath(pDocument, "/primitive2D/transform/mask[2]/polypolygoncolor", 
"color", "#ff0000");
+    assertXPath(pDocument, 
"/primitive2D/transform/mask[2]/polypolygoncolor/polypolygon/polygon/point", 5);
+}
+
 void Test::testi125329()
 {
     //Check style inherit from * css element
diff --git a/svgio/qa/cppunit/data/ClipRule.svg 
b/svgio/qa/cppunit/data/ClipRule.svg
new file mode 100644
index 000000000000..55f0cb9eee3a
--- /dev/null
+++ b/svgio/qa/cppunit/data/ClipRule.svg
@@ -0,0 +1,18 @@
+<svg version="1.1" baseProfile="basic" id="svg-root"
+  width="100%" height="100%" viewBox="0 0 480 360"
+  xmlns="http://www.w3.org/2000/svg"; 
xmlns:xlink="http://www.w3.org/1999/xlink";>
+  <!-- Define star path -->
+  <defs>
+    <path d="M50,0 21,90 98,35 2,35 79,90z" id="star" />
+  </defs>
+  <clipPath id="emptyStar">
+    <use xlink:href="#star" clip-rule="evenodd" />
+  </clipPath>
+  <rect clip-path="url(#emptyStar)" width="50" height="90" fill="blue" />
+
+  <clipPath id="filledStar">
+    <use xlink:href="#star" clip-rule="evenodd" />
+  </clipPath>
+  <rect clip-path="url(#filledStar)" width="50" height="90" x="50" fill="red" 
/>
+</svg>
+
diff --git a/svgio/source/svgreader/svgstyleattributes.cxx 
b/svgio/source/svgreader/svgstyleattributes.cxx
index 6ad1b1d25cc2..c787c4dffa92 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -1125,17 +1125,18 @@ namespace svgio::svgreader
             {
                 // create fill
                 basegfx::B2DPolyPolygon aPath(rPath);
-                const bool bNeedToCheckClipRule(SVGToken::Path == 
mrOwner.getType() || SVGToken::Polygon == mrOwner.getType());
-                const bool bClipPathIsNonzero(bNeedToCheckClipRule && 
mbIsClipPathContent && FillRule::nonzero == maClipRule);
-                const bool bFillRuleIsNonzero(bNeedToCheckClipRule && 
!mbIsClipPathContent && FillRule::nonzero == getFillRule());
 
-                if(bClipPathIsNonzero || bFillRuleIsNonzero)
+                if(SVGToken::Path == mrOwner.getType() || SVGToken::Polygon == 
mrOwner.getType())
                 {
-                    if(getFill() || getSvgGradientNodeFill() || 
getSvgPatternNodeFill()) {
-                        // nonzero is wanted, solve geometrically (see 
description on basegfx)
-                        // basegfx::utils::createNonzeroConform() is expensive 
for huge paths
-                        // and is only needed if path will be filled later on
-                        aPath = basegfx::utils::createNonzeroConform(aPath);
+                    if(FillRule::evenodd != getClipRule() && FillRule::evenodd 
!= getFillRule())
+                    {
+                        if(getFill() || getSvgGradientNodeFill() || 
getSvgPatternNodeFill())
+                        {
+                            // nonzero is wanted, solve geometrically (see 
description on basegfx)
+                            // basegfx::utils::createNonzeroConform() is 
expensive for huge paths
+                            // and is only needed if path will be filled later 
on
+                            aPath = 
basegfx::utils::createNonzeroConform(aPath);
+                        }
                     }
                 }
 
@@ -1275,10 +1276,10 @@ namespace svgio::svgreader
             mpMarkerMidXLink(nullptr),
             mpMarkerEndXLink(nullptr),
             maFillRule(FillRule::notset),
-            maClipRule(FillRule::nonzero),
+            maClipRule(FillRule::notset),
             maBaselineShift(BaselineShift::Baseline),
             maBaselineShiftNumber(0),
-            maResolvingParent(31, 0),
+            maResolvingParent(32, 0),
             mbIsClipPathContent(SVGToken::ClipPathNode == mrOwner.getType()),
             mbStrokeDasharraySet(false)
         {
@@ -2348,6 +2349,27 @@ namespace svgio::svgreader
             return FillRule::nonzero;
         }
 
+        FillRule SvgStyleAttributes::getClipRule() const
+        {
+            if(FillRule::notset != maClipRule)
+            {
+                return maClipRule;
+            }
+
+            const SvgStyleAttributes* pSvgStyleAttributes = getParentStyle();
+
+            if (pSvgStyleAttributes && maResolvingParent[31] < 
nStyleDepthLimit)
+            {
+                ++maResolvingParent[31];
+                auto ret = pSvgStyleAttributes->getClipRule();
+                --maResolvingParent[31];
+                return ret;
+            }
+
+            // default is NonZero
+            return FillRule::nonzero;
+        }
+
         const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const
         {
             if(!maStrokeDasharray.empty())

Reply via email to