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 ddd79065bd3844397c05aa2150269201526984c2
Author:     Xisco Fauli <[email protected]>
AuthorDate: Thu Jul 28 18:37:32 2022 +0200
Commit:     Christian Lohmaier <[email protected]>
CommitDate: Thu Aug 18 19:19:42 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 <[email protected]>
    Signed-off-by: Xisco Fauli <[email protected]>
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137586
    (cherry picked from commit 2b22203c0be09e9685cf081f0a1fafa538a21294)
    Reviewed-on: https://gerrit.libreoffice.org/c/core/+/137973
    Reviewed-by: Christian Lohmaier <[email protected]>

diff --git a/svgio/inc/svgstyleattributes.hxx b/svgio/inc/svgstyleattributes.hxx
index 8db2fa0676f6..dd5c16daab43 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 f9fc88f812de..cc4aae90bd39 100644
--- a/svgio/qa/cppunit/SvgImportTest.cxx
+++ b/svgio/qa/cppunit/SvgImportTest.cxx
@@ -62,6 +62,7 @@ class Test : public test::BootstrapFixture, public 
XmlTestTools
     void testClipPathAndParentStyle();
     void testClipPathAndStyle();
     void testClipPathUsingClipPath();
+    void testClipRule();
     void testi125329();
     void testMaskingPath07b();
     void test123926();
@@ -103,6 +104,7 @@ public:
     CPPUNIT_TEST(testClipPathAndParentStyle);
     CPPUNIT_TEST(testClipPathAndStyle);
     CPPUNIT_TEST(testClipPathUsingClipPath);
+    CPPUNIT_TEST(testClipRule);
     CPPUNIT_TEST(testi125329);
     CPPUNIT_TEST(testMaskingPath07b);
     CPPUNIT_TEST(test123926);
@@ -624,6 +626,28 @@ void Test::testClipPathUsingClipPath()
     assertXPath(pDocument, 
"/primitive2D/transform/mask/mask/polypolygon/polygon/point", 13);
 }
 
+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(comphelper::sequenceToContainer<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 8084ed5f0239..333ff7dbd317 100644
--- a/svgio/source/svgreader/svgstyleattributes.cxx
+++ b/svgio/source/svgreader/svgstyleattributes.cxx
@@ -1117,17 +1117,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);
+                        }
                     }
                 }
 
@@ -1267,10 +1268,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)
         {
@@ -2341,6 +2342,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