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 <xiscofauli@libreoffice.org>
This commit is contained in:
parent
d07f18e0c3
commit
4f61276dae
4 changed files with 78 additions and 11 deletions
|
@ -338,6 +338,9 @@ namespace svgio::svgreader
|
||||||
/// fill rule content
|
/// fill rule content
|
||||||
FillRule getFillRule() const;
|
FillRule getFillRule() const;
|
||||||
|
|
||||||
|
/// clip rule content
|
||||||
|
FillRule getClipRule() const;
|
||||||
|
|
||||||
/// fill StrokeDasharray content
|
/// fill StrokeDasharray content
|
||||||
const SvgNumberVector& getStrokeDasharray() const;
|
const SvgNumberVector& getStrokeDasharray() const;
|
||||||
|
|
||||||
|
|
|
@ -66,6 +66,7 @@ class Test : public test::BootstrapFixture, public XmlTestTools
|
||||||
void testShapeWithClipPath();
|
void testShapeWithClipPath();
|
||||||
void testClipPathUsingClipPath();
|
void testClipPathUsingClipPath();
|
||||||
void testFillRule();
|
void testFillRule();
|
||||||
|
void testClipRule();
|
||||||
void testi125329();
|
void testi125329();
|
||||||
void testMaskingPath07b();
|
void testMaskingPath07b();
|
||||||
void test123926();
|
void test123926();
|
||||||
|
@ -112,6 +113,7 @@ public:
|
||||||
CPPUNIT_TEST(testShapeWithClipPath);
|
CPPUNIT_TEST(testShapeWithClipPath);
|
||||||
CPPUNIT_TEST(testClipPathUsingClipPath);
|
CPPUNIT_TEST(testClipPathUsingClipPath);
|
||||||
CPPUNIT_TEST(testFillRule);
|
CPPUNIT_TEST(testFillRule);
|
||||||
|
CPPUNIT_TEST(testClipRule);
|
||||||
CPPUNIT_TEST(testi125329);
|
CPPUNIT_TEST(testi125329);
|
||||||
CPPUNIT_TEST(testMaskingPath07b);
|
CPPUNIT_TEST(testMaskingPath07b);
|
||||||
CPPUNIT_TEST(test123926);
|
CPPUNIT_TEST(test123926);
|
||||||
|
@ -719,6 +721,28 @@ void Test::testFillRule()
|
||||||
assertXPath(pDocument, "/primitive2D/transform/polypolygonstroke/polypolygon/polygon", 2);
|
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()
|
void Test::testi125329()
|
||||||
{
|
{
|
||||||
//Check style inherit from * css element
|
//Check style inherit from * css element
|
||||||
|
|
18
svgio/qa/cppunit/data/ClipRule.svg
Normal file
18
svgio/qa/cppunit/data/ClipRule.svg
Normal file
|
@ -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>
|
||||||
|
|
After Width: | Height: | Size: 640 B |
|
@ -1125,17 +1125,18 @@ namespace svgio::svgreader
|
||||||
{
|
{
|
||||||
// create fill
|
// create fill
|
||||||
basegfx::B2DPolyPolygon aPath(rPath);
|
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()) {
|
if(FillRule::evenodd != getClipRule() && FillRule::evenodd != getFillRule())
|
||||||
// nonzero is wanted, solve geometrically (see description on basegfx)
|
{
|
||||||
// basegfx::utils::createNonzeroConform() is expensive for huge paths
|
if(getFill() || getSvgGradientNodeFill() || getSvgPatternNodeFill())
|
||||||
// and is only needed if path will be filled later on
|
{
|
||||||
aPath = basegfx::utils::createNonzeroConform(aPath);
|
// 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),
|
mpMarkerMidXLink(nullptr),
|
||||||
mpMarkerEndXLink(nullptr),
|
mpMarkerEndXLink(nullptr),
|
||||||
maFillRule(FillRule::notset),
|
maFillRule(FillRule::notset),
|
||||||
maClipRule(FillRule::nonzero),
|
maClipRule(FillRule::notset),
|
||||||
maBaselineShift(BaselineShift::Baseline),
|
maBaselineShift(BaselineShift::Baseline),
|
||||||
maBaselineShiftNumber(0),
|
maBaselineShiftNumber(0),
|
||||||
maResolvingParent(31, 0),
|
maResolvingParent(32, 0),
|
||||||
mbIsClipPathContent(SVGToken::ClipPathNode == mrOwner.getType()),
|
mbIsClipPathContent(SVGToken::ClipPathNode == mrOwner.getType()),
|
||||||
mbStrokeDasharraySet(false)
|
mbStrokeDasharraySet(false)
|
||||||
{
|
{
|
||||||
|
@ -2348,6 +2349,27 @@ namespace svgio::svgreader
|
||||||
return FillRule::nonzero;
|
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
|
const SvgNumberVector& SvgStyleAttributes::getStrokeDasharray() const
|
||||||
{
|
{
|
||||||
if(!maStrokeDasharray.empty())
|
if(!maStrokeDasharray.empty())
|
||||||
|
|
Loading…
Reference in a new issue