aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/svg
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2016-12-01 13:35:11 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-12-06 16:05:41 +0000
commite932d4b3a99905a6272c5574f21ac651632f4e82 (patch)
tree667289b43423b6183ac76eb657b32aef201b1b13 /experimental/svg
parentebe79ffd8627e3fea945a82895e64cede4ec21bf (diff)
[SVGDom] Add fill-rule support
There's a bit of friction with this attribute, because per spec it is an inherited presentation attribute, but in Skia it is part of the actual SkPath state. So we must add some plumbing to SkSVGShape & friends to allow overriding the fill type at render-time. R=robertphillips@google.com,stephana@google.com Change-Id: I9c926d653c6211beb3914bffac50d4349dbdd2c0 Reviewed-on: https://skia-review.googlesource.com/5415 Reviewed-by: Mike Reed <reed@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'experimental/svg')
-rw-r--r--experimental/svg/model/SkSVGAttribute.cpp1
-rw-r--r--experimental/svg/model/SkSVGAttribute.h2
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.cpp23
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.h1
-rw-r--r--experimental/svg/model/SkSVGCircle.cpp2
-rw-r--r--experimental/svg/model/SkSVGCircle.h3
-rw-r--r--experimental/svg/model/SkSVGDOM.cpp13
-rw-r--r--experimental/svg/model/SkSVGEllipse.cpp2
-rw-r--r--experimental/svg/model/SkSVGEllipse.h3
-rw-r--r--experimental/svg/model/SkSVGLine.cpp2
-rw-r--r--experimental/svg/model/SkSVGLine.h3
-rw-r--r--experimental/svg/model/SkSVGNode.cpp9
-rw-r--r--experimental/svg/model/SkSVGNode.h1
-rw-r--r--experimental/svg/model/SkSVGPath.cpp5
-rw-r--r--experimental/svg/model/SkSVGPath.h5
-rw-r--r--experimental/svg/model/SkSVGPoly.cpp6
-rw-r--r--experimental/svg/model/SkSVGPoly.h5
-rw-r--r--experimental/svg/model/SkSVGRect.cpp2
-rw-r--r--experimental/svg/model/SkSVGRect.h3
-rw-r--r--experimental/svg/model/SkSVGRenderContext.cpp9
-rw-r--r--experimental/svg/model/SkSVGRenderContext.h2
-rw-r--r--experimental/svg/model/SkSVGShape.cpp19
-rw-r--r--experimental/svg/model/SkSVGShape.h6
-rw-r--r--experimental/svg/model/SkSVGTypes.h23
-rw-r--r--experimental/svg/model/SkSVGValue.h2
25 files changed, 135 insertions, 17 deletions
diff --git a/experimental/svg/model/SkSVGAttribute.cpp b/experimental/svg/model/SkSVGAttribute.cpp
index 9d6b193e04..4935d6afcf 100644
--- a/experimental/svg/model/SkSVGAttribute.cpp
+++ b/experimental/svg/model/SkSVGAttribute.cpp
@@ -12,6 +12,7 @@ SkSVGPresentationAttributes SkSVGPresentationAttributes::MakeInitial() {
result.fFill.set(SkSVGPaint(SkSVGColorType(SK_ColorBLACK)));
result.fFillOpacity.set(SkSVGNumberType(1));
+ result.fFillRule.set(SkSVGFillRule(SkSVGFillRule::Type::kNonZero));
result.fStroke.set(SkSVGPaint(SkSVGPaint::Type::kNone));
result.fStrokeLineCap.set(SkSVGLineCap(SkSVGLineCap::Type::kButt));
diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h
index 478a26b261..93c5f99153 100644
--- a/experimental/svg/model/SkSVGAttribute.h
+++ b/experimental/svg/model/SkSVGAttribute.h
@@ -19,6 +19,7 @@ enum class SkSVGAttribute {
kD,
kFill,
kFillOpacity,
+ kFillRule,
kGradientTransform,
kHeight,
kHref,
@@ -56,6 +57,7 @@ struct SkSVGPresentationAttributes {
SkTLazy<SkSVGPaint> fFill;
SkTLazy<SkSVGNumberType> fFillOpacity;
+ SkTLazy<SkSVGFillRule> fFillRule;
SkTLazy<SkSVGPaint> fStroke;
SkTLazy<SkSVGLineCap> fStrokeLineCap;
diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp
index 04b050828a..5ca317ccc3 100644
--- a/experimental/svg/model/SkSVGAttributeParser.cpp
+++ b/experimental/svg/model/SkSVGAttributeParser.cpp
@@ -551,3 +551,26 @@ bool SkSVGAttributeParser::parsePoints(SkSVGPointsType* points) {
return false;
}
+
+// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
+bool SkSVGAttributeParser::parseFillRule(SkSVGFillRule* fillRule) {
+ static const struct {
+ SkSVGFillRule::Type fType;
+ const char* fName;
+ } gFillRuleInfo[] = {
+ { SkSVGFillRule::Type::kNonZero, "nonzero" },
+ { SkSVGFillRule::Type::kEvenOdd, "evenodd" },
+ { SkSVGFillRule::Type::kInherit, "inherit" },
+ };
+
+ bool parsedValue = false;
+ for (size_t i = 0; i < SK_ARRAY_COUNT(gFillRuleInfo); ++i) {
+ if (this->parseExpectedStringToken(gFillRuleInfo[i].fName)) {
+ *fillRule = SkSVGFillRule(gFillRuleInfo[i].fType);
+ parsedValue = true;
+ break;
+ }
+ }
+
+ return parsedValue && this->parseEOSToken();
+}
diff --git a/experimental/svg/model/SkSVGAttributeParser.h b/experimental/svg/model/SkSVGAttributeParser.h
index 9d6939b2e2..2ffa79f543 100644
--- a/experimental/svg/model/SkSVGAttributeParser.h
+++ b/experimental/svg/model/SkSVGAttributeParser.h
@@ -15,6 +15,7 @@ public:
SkSVGAttributeParser(const char[]);
bool parseColor(SkSVGColorType*);
+ bool parseFillRule(SkSVGFillRule*);
bool parseNumber(SkSVGNumberType*);
bool parseLength(SkSVGLength*);
bool parseViewBox(SkSVGViewBoxType*);
diff --git a/experimental/svg/model/SkSVGCircle.cpp b/experimental/svg/model/SkSVGCircle.cpp
index 692cd9ff54..9d8117379a 100644
--- a/experimental/svg/model/SkSVGCircle.cpp
+++ b/experimental/svg/model/SkSVGCircle.cpp
@@ -47,7 +47,7 @@ void SkSVGCircle::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
void SkSVGCircle::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
- const SkPaint& paint) const {
+ const SkPaint& paint, SkPath::FillType) const {
const auto cx = lctx.resolve(fCx, SkSVGLengthContext::LengthType::kHorizontal);
const auto cy = lctx.resolve(fCy, SkSVGLengthContext::LengthType::kVertical);
const auto r = lctx.resolve(fR , SkSVGLengthContext::LengthType::kOther);
diff --git a/experimental/svg/model/SkSVGCircle.h b/experimental/svg/model/SkSVGCircle.h
index ef1bd2aadb..02aaad4891 100644
--- a/experimental/svg/model/SkSVGCircle.h
+++ b/experimental/svg/model/SkSVGCircle.h
@@ -23,7 +23,8 @@ public:
protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
- void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const override;
+ void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
+ SkPath::FillType) const override;
private:
SkSVGCircle();
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp
index c9745f1730..2120f80e36 100644
--- a/experimental/svg/model/SkSVGDOM.cpp
+++ b/experimental/svg/model/SkSVGDOM.cpp
@@ -173,6 +173,18 @@ bool SetPointsAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
return true;
}
+bool SetFillRuleAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGFillRule fillRule;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseFillRule(&fillRule)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGFillRuleValue(fillRule));
+ return true;
+}
+
SkString TrimmedString(const char* first, const char* last) {
SkASSERT(first);
SkASSERT(last);
@@ -256,6 +268,7 @@ SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
{ "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
{ "fill" , { SkSVGAttribute::kFill , SetPaintAttribute }},
{ "fill-opacity" , { SkSVGAttribute::kFillOpacity , SetNumberAttribute }},
+ { "fill-rule" , { SkSVGAttribute::kFillRule , SetFillRuleAttribute }},
{ "gradientTransform", { SkSVGAttribute::kGradientTransform, SetTransformAttribute }},
{ "height" , { SkSVGAttribute::kHeight , SetLengthAttribute }},
{ "offset" , { SkSVGAttribute::kOffset , SetLengthAttribute }},
diff --git a/experimental/svg/model/SkSVGEllipse.cpp b/experimental/svg/model/SkSVGEllipse.cpp
index f7461b8cd7..481af5c3ab 100644
--- a/experimental/svg/model/SkSVGEllipse.cpp
+++ b/experimental/svg/model/SkSVGEllipse.cpp
@@ -56,7 +56,7 @@ void SkSVGEllipse::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
void SkSVGEllipse::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
- const SkPaint& paint) const {
+ const SkPaint& paint, SkPath::FillType) const {
const auto cx = lctx.resolve(fCx, SkSVGLengthContext::LengthType::kHorizontal);
const auto cy = lctx.resolve(fCy, SkSVGLengthContext::LengthType::kVertical);
const auto rx = lctx.resolve(fRx, SkSVGLengthContext::LengthType::kHorizontal);
diff --git a/experimental/svg/model/SkSVGEllipse.h b/experimental/svg/model/SkSVGEllipse.h
index 640d7f6f26..0042b3364e 100644
--- a/experimental/svg/model/SkSVGEllipse.h
+++ b/experimental/svg/model/SkSVGEllipse.h
@@ -24,7 +24,8 @@ public:
protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
- void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const override;
+ void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
+ SkPath::FillType) const override;
private:
SkSVGEllipse();
diff --git a/experimental/svg/model/SkSVGLine.cpp b/experimental/svg/model/SkSVGLine.cpp
index 030aad8db4..27cdd469d2 100644
--- a/experimental/svg/model/SkSVGLine.cpp
+++ b/experimental/svg/model/SkSVGLine.cpp
@@ -56,7 +56,7 @@ void SkSVGLine::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
void SkSVGLine::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
- const SkPaint& paint) const {
+ const SkPaint& paint, SkPath::FillType) const {
const auto x1 = lctx.resolve(fX1, SkSVGLengthContext::LengthType::kHorizontal);
const auto y1 = lctx.resolve(fY1, SkSVGLengthContext::LengthType::kVertical);
const auto x2 = lctx.resolve(fX2, SkSVGLengthContext::LengthType::kHorizontal);
diff --git a/experimental/svg/model/SkSVGLine.h b/experimental/svg/model/SkSVGLine.h
index c2716e00e2..524fc2ac0e 100644
--- a/experimental/svg/model/SkSVGLine.h
+++ b/experimental/svg/model/SkSVGLine.h
@@ -24,7 +24,8 @@ public:
protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
- void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const override;
+ void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
+ SkPath::FillType) const override;
private:
SkSVGLine();
diff --git a/experimental/svg/model/SkSVGNode.cpp b/experimental/svg/model/SkSVGNode.cpp
index f40ee5dadb..a5c8147554 100644
--- a/experimental/svg/model/SkSVGNode.cpp
+++ b/experimental/svg/model/SkSVGNode.cpp
@@ -49,6 +49,10 @@ void SkSVGNode::setFillOpacity(const SkSVGNumberType& opacity) {
SkSVGNumberType(SkTPin<SkScalar>(opacity.value(), 0, 1)));
}
+void SkSVGNode::setFillRule(const SkSVGFillRule& fillRule) {
+ fPresentationAttributes.fFillRule.set(fillRule);
+}
+
void SkSVGNode::setOpacity(const SkSVGNumberType& opacity) {
fPresentationAttributes.fOpacity.set(
SkSVGNumberType(SkTPin<SkScalar>(opacity.value(), 0, 1)));
@@ -79,6 +83,11 @@ void SkSVGNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
this->setFillOpacity(*opacity);
}
break;
+ case SkSVGAttribute::kFillRule:
+ if (const SkSVGFillRuleValue* fillRule = v.as<SkSVGFillRuleValue>()) {
+ this->setFillRule(*fillRule);
+ }
+ break;
case SkSVGAttribute::kOpacity:
if (const SkSVGNumberValue* opacity = v.as<SkSVGNumberValue>()) {
this->setOpacity(*opacity);
diff --git a/experimental/svg/model/SkSVGNode.h b/experimental/svg/model/SkSVGNode.h
index 2a7c836413..1e092a4d87 100644
--- a/experimental/svg/model/SkSVGNode.h
+++ b/experimental/svg/model/SkSVGNode.h
@@ -47,6 +47,7 @@ public:
void setFill(const SkSVGPaint&);
void setFillOpacity(const SkSVGNumberType&);
+ void setFillRule(const SkSVGFillRule&);
void setOpacity(const SkSVGNumberType&);
void setStroke(const SkSVGPaint&);
void setStrokeOpacity(const SkSVGNumberType&);
diff --git a/experimental/svg/model/SkSVGPath.cpp b/experimental/svg/model/SkSVGPath.cpp
index 07e0a3e545..dd248237f1 100644
--- a/experimental/svg/model/SkSVGPath.cpp
+++ b/experimental/svg/model/SkSVGPath.cpp
@@ -25,6 +25,9 @@ void SkSVGPath::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
}
-void SkSVGPath::onDraw(SkCanvas* canvas, const SkSVGLengthContext&, const SkPaint& paint) const {
+void SkSVGPath::onDraw(SkCanvas* canvas, const SkSVGLengthContext&, const SkPaint& paint,
+ SkPath::FillType fillType) const {
+ // the passed fillType follows inheritance rules and needs to be applied at draw time.
+ fPath.setFillType(fillType);
canvas->drawPath(fPath, paint);
}
diff --git a/experimental/svg/model/SkSVGPath.h b/experimental/svg/model/SkSVGPath.h
index e72f0d137e..8297a8d557 100644
--- a/experimental/svg/model/SkSVGPath.h
+++ b/experimental/svg/model/SkSVGPath.h
@@ -21,12 +21,13 @@ public:
protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
- void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const override;
+ void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
+ SkPath::FillType) const override;
private:
SkSVGPath();
- SkPath fPath;
+ mutable SkPath fPath; // mutated in onDraw(), to apply inherited fill types.
typedef SkSVGShape INHERITED;
};
diff --git a/experimental/svg/model/SkSVGPoly.cpp b/experimental/svg/model/SkSVGPoly.cpp
index bcc716f362..826ca2457e 100644
--- a/experimental/svg/model/SkSVGPoly.cpp
+++ b/experimental/svg/model/SkSVGPoly.cpp
@@ -6,6 +6,7 @@
*/
#include "SkCanvas.h"
+#include "SkTLazy.h"
#include "SkSVGRenderContext.h"
#include "SkSVGPoly.h"
#include "SkSVGValue.h"
@@ -31,6 +32,9 @@ void SkSVGPoly::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
}
-void SkSVGPoly::onDraw(SkCanvas* canvas, const SkSVGLengthContext&, const SkPaint& paint) const {
+void SkSVGPoly::onDraw(SkCanvas* canvas, const SkSVGLengthContext&, const SkPaint& paint,
+ SkPath::FillType fillType) const {
+ // the passed fillType follows inheritance rules and needs to be applied at draw time.
+ fPath.setFillType(fillType);
canvas->drawPath(fPath, paint);
}
diff --git a/experimental/svg/model/SkSVGPoly.h b/experimental/svg/model/SkSVGPoly.h
index 3ae8dc6f02..f75d3626cc 100644
--- a/experimental/svg/model/SkSVGPoly.h
+++ b/experimental/svg/model/SkSVGPoly.h
@@ -29,12 +29,13 @@ public:
protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
- void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const override;
+ void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
+ SkPath::FillType) const override;
private:
SkSVGPoly(SkSVGTag);
- SkPath fPath;
+ mutable SkPath fPath; // mutated in onDraw(), to apply inherited fill types.
typedef SkSVGShape INHERITED;
};
diff --git a/experimental/svg/model/SkSVGRect.cpp b/experimental/svg/model/SkSVGRect.cpp
index cbb18306a5..1afd9957c6 100644
--- a/experimental/svg/model/SkSVGRect.cpp
+++ b/experimental/svg/model/SkSVGRect.cpp
@@ -75,7 +75,7 @@ void SkSVGRect::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
void SkSVGRect::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
- const SkPaint& paint) const {
+ const SkPaint& paint, SkPath::FillType) const {
const SkRect rect = lctx.resolveRect(fX, fY, fWidth, fHeight);
const SkScalar rx = lctx.resolve(fRx, SkSVGLengthContext::LengthType::kHorizontal);
const SkScalar ry = lctx.resolve(fRy, SkSVGLengthContext::LengthType::kVertical);
diff --git a/experimental/svg/model/SkSVGRect.h b/experimental/svg/model/SkSVGRect.h
index 0da248c4eb..affa65f610 100644
--- a/experimental/svg/model/SkSVGRect.h
+++ b/experimental/svg/model/SkSVGRect.h
@@ -26,7 +26,8 @@ public:
protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
- void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const override;
+ void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
+ SkPath::FillType) const override;
private:
SkSVGRect();
diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp
index 147d64edb3..fd0262319a 100644
--- a/experimental/svg/model/SkSVGRenderContext.cpp
+++ b/experimental/svg/model/SkSVGRenderContext.cpp
@@ -6,6 +6,7 @@
*/
#include "SkCanvas.h"
+#include "SkPath.h"
#include "SkSVGAttribute.h"
#include "SkSVGNode.h"
#include "SkSVGRenderContext.h"
@@ -188,6 +189,13 @@ void commitToPaint<SkSVGAttribute::kStrokeWidth>(const SkSVGPresentationAttribut
pctx->fStrokePaint.setStrokeWidth(strokeWidth);
}
+template <>
+void commitToPaint<SkSVGAttribute::kFillRule>(const SkSVGPresentationAttributes&,
+ const SkSVGRenderContext&,
+ SkSVGPresentationContext*) {
+ // Not part of the SkPaint state; applied to the path at render time.
+}
+
} // anonymous ns
SkSVGPresentationContext::SkSVGPresentationContext()
@@ -258,6 +266,7 @@ void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
ApplyLazyInheritedAttribute(Fill);
ApplyLazyInheritedAttribute(FillOpacity);
+ ApplyLazyInheritedAttribute(FillRule);
ApplyLazyInheritedAttribute(Stroke);
ApplyLazyInheritedAttribute(StrokeLineCap);
ApplyLazyInheritedAttribute(StrokeLineJoin);
diff --git a/experimental/svg/model/SkSVGRenderContext.h b/experimental/svg/model/SkSVGRenderContext.h
index 393c2849eb..9d2fb3a621 100644
--- a/experimental/svg/model/SkSVGRenderContext.h
+++ b/experimental/svg/model/SkSVGRenderContext.h
@@ -65,6 +65,8 @@ public:
const SkSVGLengthContext& lengthContext() const { return *fLengthContext; }
SkSVGLengthContext* writableLengthContext() { return fLengthContext.writable(); }
+ const SkSVGPresentationContext& presentationContext() const { return *fPresentationContext; }
+
SkCanvas* canvas() const { return fCanvas; }
enum ApplyFlags {
diff --git a/experimental/svg/model/SkSVGShape.cpp b/experimental/svg/model/SkSVGShape.cpp
index 38af4c9303..9351a2f096 100644
--- a/experimental/svg/model/SkSVGShape.cpp
+++ b/experimental/svg/model/SkSVGShape.cpp
@@ -11,16 +11,31 @@
SkSVGShape::SkSVGShape(SkSVGTag t) : INHERITED(t) {}
void SkSVGShape::onRender(const SkSVGRenderContext& ctx) const {
+ const SkPath::FillType fillType =
+ FillRuleToFillType(*ctx.presentationContext().fInherited.fFillRule.get());
+
// TODO: this approach forces duplicate geometry resolution in onDraw(); refactor to avoid.
if (const SkPaint* fillPaint = ctx.fillPaint()) {
- this->onDraw(ctx.canvas(), ctx.lengthContext(), *fillPaint);
+ this->onDraw(ctx.canvas(), ctx.lengthContext(), *fillPaint, fillType);
}
if (const SkPaint* strokePaint = ctx.strokePaint()) {
- this->onDraw(ctx.canvas(), ctx.lengthContext(), *strokePaint);
+ this->onDraw(ctx.canvas(), ctx.lengthContext(), *strokePaint, fillType);
}
}
void SkSVGShape::appendChild(sk_sp<SkSVGNode>) {
SkDebugf("cannot append child nodes to an SVG shape.\n");
}
+
+SkPath::FillType SkSVGShape::FillRuleToFillType(const SkSVGFillRule& fillRule) {
+ switch (fillRule.type()) {
+ case SkSVGFillRule::Type::kNonZero:
+ return SkPath::kWinding_FillType;
+ case SkSVGFillRule::Type::kEvenOdd:
+ return SkPath::kEvenOdd_FillType;
+ default:
+ SkASSERT(false);
+ return SkPath::kWinding_FillType;
+ }
+}
diff --git a/experimental/svg/model/SkSVGShape.h b/experimental/svg/model/SkSVGShape.h
index 1f3c4555c3..48b2ead0c1 100644
--- a/experimental/svg/model/SkSVGShape.h
+++ b/experimental/svg/model/SkSVGShape.h
@@ -8,6 +8,7 @@
#ifndef SkSVGShape_DEFINED
#define SkSVGShape_DEFINED
+#include "SkPath.h"
#include "SkSVGTransformableNode.h"
class SkSVGLengthContext;
@@ -24,7 +25,10 @@ protected:
void onRender(const SkSVGRenderContext&) const final;
- virtual void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const = 0;
+ virtual void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
+ SkPath::FillType) const = 0;
+
+ static SkPath::FillType FillRuleToFillType(const SkSVGFillRule&);
private:
typedef SkSVGTransformableNode INHERITED;
diff --git a/experimental/svg/model/SkSVGTypes.h b/experimental/svg/model/SkSVGTypes.h
index b07f9a2c8c..d5d2b7146f 100644
--- a/experimental/svg/model/SkSVGTypes.h
+++ b/experimental/svg/model/SkSVGTypes.h
@@ -191,4 +191,27 @@ private:
Type fType;
};
+class SkSVGFillRule {
+public:
+ enum class Type {
+ kNonZero,
+ kEvenOdd,
+ kInherit,
+ };
+
+ constexpr SkSVGFillRule() : fType(Type::kInherit) {}
+ constexpr explicit SkSVGFillRule(Type t) : fType(t) {}
+
+ SkSVGFillRule(const SkSVGFillRule&) = default;
+ SkSVGFillRule& operator=(const SkSVGFillRule&) = default;
+
+ bool operator==(const SkSVGFillRule& other) const { return fType == other.fType; }
+ bool operator!=(const SkSVGFillRule& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+
+private:
+ Type fType;
+};
+
#endif // SkSVGTypes_DEFINED
diff --git a/experimental/svg/model/SkSVGValue.h b/experimental/svg/model/SkSVGValue.h
index 0160af0371..9f3095c918 100644
--- a/experimental/svg/model/SkSVGValue.h
+++ b/experimental/svg/model/SkSVGValue.h
@@ -18,6 +18,7 @@ class SkSVGValue : public SkNoncopyable {
public:
enum class Type {
kColor,
+ kFillRule,
kLength,
kLineCap,
kLineJoin,
@@ -70,6 +71,7 @@ private:
};
using SkSVGColorValue = SkSVGWrapperValue<SkSVGColorType , SkSVGValue::Type::kColor >;
+using SkSVGFillRuleValue = SkSVGWrapperValue<SkSVGFillRule , SkSVGValue::Type::kFillRule >;
using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength , SkSVGValue::Type::kLength >;
using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >;
using SkSVGTransformValue = SkSVGWrapperValue<SkSVGTransformType, SkSVGValue::Type::kTransform>;