aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/svg
diff options
context:
space:
mode:
authorGravatar Florin Malita <fmalita@chromium.org>2016-12-08 09:26:47 -0500
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2016-12-08 15:00:18 +0000
commitce8840e3842f3a702c5d7bf440ff730bdfaf8e70 (patch)
tree0a94cdeb3d2d8632644490b70fdb0c40d185b8ec /experimental/svg
parentc5a8366d9922902cffbd351fdd15755dd2ac99bf (diff)
[SVGDom] ClipPath support
* clip-path attribute handling * clipPath container element * asPath() SkSVGNode virtual for capturing subtree geometry R=robertphillips@google.com,stephana@google.com Change-Id: I9597534fe3047b631da6309eafac055dff5696e9 Reviewed-on: https://skia-review.googlesource.com/5650 Reviewed-by: Robert Phillips <robertphillips@google.com> Commit-Queue: Florin Malita <fmalita@chromium.org>
Diffstat (limited to 'experimental/svg')
-rw-r--r--experimental/svg/model/SkSVGAttribute.h3
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.cpp19
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.h1
-rw-r--r--experimental/svg/model/SkSVGCircle.cpp25
-rw-r--r--experimental/svg/model/SkSVGCircle.h7
-rw-r--r--experimental/svg/model/SkSVGClipPath.cpp10
-rw-r--r--experimental/svg/model/SkSVGClipPath.h29
-rw-r--r--experimental/svg/model/SkSVGContainer.cpp16
-rw-r--r--experimental/svg/model/SkSVGContainer.h2
-rw-r--r--experimental/svg/model/SkSVGDOM.cpp16
-rw-r--r--experimental/svg/model/SkSVGEllipse.cpp22
-rw-r--r--experimental/svg/model/SkSVGEllipse.h6
-rw-r--r--experimental/svg/model/SkSVGLine.cpp28
-rw-r--r--experimental/svg/model/SkSVGLine.h7
-rw-r--r--experimental/svg/model/SkSVGNode.cpp14
-rw-r--r--experimental/svg/model/SkSVGNode.h6
-rw-r--r--experimental/svg/model/SkSVGPath.cpp9
-rw-r--r--experimental/svg/model/SkSVGPath.h2
-rw-r--r--experimental/svg/model/SkSVGPoly.cpp9
-rw-r--r--experimental/svg/model/SkSVGPoly.h2
-rw-r--r--experimental/svg/model/SkSVGRect.cpp23
-rw-r--r--experimental/svg/model/SkSVGRect.h6
-rw-r--r--experimental/svg/model/SkSVGRenderContext.cpp24
-rw-r--r--experimental/svg/model/SkSVGRenderContext.h1
-rw-r--r--experimental/svg/model/SkSVGTransformableNode.cpp13
-rw-r--r--experimental/svg/model/SkSVGTransformableNode.h2
-rw-r--r--experimental/svg/model/SkSVGTypes.h28
-rw-r--r--experimental/svg/model/SkSVGValue.h2
28 files changed, 312 insertions, 20 deletions
diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h
index 93c5f99153..2900a03f7c 100644
--- a/experimental/svg/model/SkSVGAttribute.h
+++ b/experimental/svg/model/SkSVGAttribute.h
@@ -14,6 +14,7 @@
class SkSVGRenderContext;
enum class SkSVGAttribute {
+ kClipPath,
kCx, // <circle>,<ellipse>: center x position
kCy, // <circle>,<ellipse>: center y position
kD,
@@ -65,7 +66,9 @@ struct SkSVGPresentationAttributes {
SkTLazy<SkSVGNumberType> fStrokeOpacity;
SkTLazy<SkSVGLength> fStrokeWidth;
+ // uninherited
SkTLazy<SkSVGNumberType> fOpacity;
+ SkTLazy<SkSVGClip> fClipPath;
};
#endif // SkSVGAttribute_DEFINED
diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp
index 5ca317ccc3..f8eef8cfa7 100644
--- a/experimental/svg/model/SkSVGAttributeParser.cpp
+++ b/experimental/svg/model/SkSVGAttributeParser.cpp
@@ -443,6 +443,25 @@ bool SkSVGAttributeParser::parsePaint(SkSVGPaint* paint) {
return parsedValue && this->parseEOSToken();
}
+// https://www.w3.org/TR/SVG/masking.html#ClipPathProperty
+bool SkSVGAttributeParser::parseClipPath(SkSVGClip* clip) {
+ SkSVGStringType iri;
+ bool parsedValue = false;
+
+ if (this->parseExpectedStringToken("none")) {
+ *clip = SkSVGClip(SkSVGClip::Type::kNone);
+ parsedValue = true;
+ } else if (this->parseExpectedStringToken("inherit")) {
+ *clip = SkSVGClip(SkSVGClip::Type::kInherit);
+ parsedValue = true;
+ } else if (this->parseFuncIRI(&iri)) {
+ *clip = SkSVGClip(iri.value());
+ parsedValue = true;
+ }
+
+ return parsedValue && this->parseEOSToken();
+}
+
// https://www.w3.org/TR/SVG/painting.html#StrokeLinecapProperty
bool SkSVGAttributeParser::parseLineCap(SkSVGLineCap* cap) {
static const struct {
diff --git a/experimental/svg/model/SkSVGAttributeParser.h b/experimental/svg/model/SkSVGAttributeParser.h
index 2ffa79f543..67c13f6b7e 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 parseClipPath(SkSVGClip*);
bool parseFillRule(SkSVGFillRule*);
bool parseNumber(SkSVGNumberType*);
bool parseLength(SkSVGLength*);
diff --git a/experimental/svg/model/SkSVGCircle.cpp b/experimental/svg/model/SkSVGCircle.cpp
index 9d8117379a..49348795ab 100644
--- a/experimental/svg/model/SkSVGCircle.cpp
+++ b/experimental/svg/model/SkSVGCircle.cpp
@@ -46,13 +46,32 @@ void SkSVGCircle::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
}
-void SkSVGCircle::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
- const SkPaint& paint, SkPath::FillType) const {
+std::tuple<SkPoint, SkScalar> SkSVGCircle::resolve(const SkSVGLengthContext& lctx) 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);
+ return std::make_tuple(SkPoint::Make(cx, cy), r);
+}
+void SkSVGCircle::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
+ const SkPaint& paint, SkPath::FillType) const {
+ SkPoint pos;
+ SkScalar r;
+ std::tie(pos, r) = this->resolve(lctx);
+
if (r > 0) {
- canvas->drawCircle(cx, cy, r, paint);
+ canvas->drawCircle(pos.x(), pos.y(), r, paint);
}
}
+
+SkPath SkSVGCircle::onAsPath(const SkSVGRenderContext& ctx) const {
+ SkPoint pos;
+ SkScalar r;
+ std::tie(pos, r) = this->resolve(ctx.lengthContext());
+
+ SkPath path;
+ path.addCircle(pos.x(), pos.y(), r);
+ this->mapToParent(&path);
+
+ return path;
+}
diff --git a/experimental/svg/model/SkSVGCircle.h b/experimental/svg/model/SkSVGCircle.h
index 02aaad4891..16ee54d280 100644
--- a/experimental/svg/model/SkSVGCircle.h
+++ b/experimental/svg/model/SkSVGCircle.h
@@ -11,6 +11,8 @@
#include "SkSVGShape.h"
#include "SkSVGTypes.h"
+struct SkPoint;
+
class SkSVGCircle final : public SkSVGShape {
public:
virtual ~SkSVGCircle() = default;
@@ -26,9 +28,14 @@ protected:
void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
SkPath::FillType) const override;
+ SkPath onAsPath(const SkSVGRenderContext&) const override;
+
private:
SkSVGCircle();
+ // resolve and return the center and radius values
+ std::tuple<SkPoint, SkScalar> resolve(const SkSVGLengthContext&) const;
+
SkSVGLength fCx = SkSVGLength(0);
SkSVGLength fCy = SkSVGLength(0);
SkSVGLength fR = SkSVGLength(0);
diff --git a/experimental/svg/model/SkSVGClipPath.cpp b/experimental/svg/model/SkSVGClipPath.cpp
new file mode 100644
index 0000000000..60f1b6a347
--- /dev/null
+++ b/experimental/svg/model/SkSVGClipPath.cpp
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSVGClipPath.h"
+
+SkSVGClipPath::SkSVGClipPath() : INHERITED(SkSVGTag::kClipPath) {}
diff --git a/experimental/svg/model/SkSVGClipPath.h b/experimental/svg/model/SkSVGClipPath.h
new file mode 100644
index 0000000000..ec4395308b
--- /dev/null
+++ b/experimental/svg/model/SkSVGClipPath.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2016 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSVGClipPath_DEFINED
+#define SkSVGClipPath_DEFINED
+
+#include "SkSVGHiddenContainer.h"
+#include "SkSVGTypes.h"
+
+class SkSVGClipPath final : public SkSVGHiddenContainer {
+public:
+ virtual ~SkSVGClipPath() = default;
+ static sk_sp<SkSVGClipPath> Make() {
+ return sk_sp<SkSVGClipPath>(new SkSVGClipPath());
+ }
+
+protected:
+
+private:
+ SkSVGClipPath();
+
+ typedef SkSVGHiddenContainer INHERITED;
+};
+
+#endif // SkSVGClipPath_DEFINED
diff --git a/experimental/svg/model/SkSVGContainer.cpp b/experimental/svg/model/SkSVGContainer.cpp
index af19608d25..9f526c22c3 100644
--- a/experimental/svg/model/SkSVGContainer.cpp
+++ b/experimental/svg/model/SkSVGContainer.cpp
@@ -7,6 +7,9 @@
#include "SkSVGContainer.h"
+#include "SkPath.h"
+#include "SkPathOps.h"
+
SkSVGContainer::SkSVGContainer(SkSVGTag t) : INHERITED(t) { }
void SkSVGContainer::appendChild(sk_sp<SkSVGNode> node) {
@@ -23,3 +26,16 @@ void SkSVGContainer::onRender(const SkSVGRenderContext& ctx) const {
fChildren[i]->render(ctx);
}
}
+
+SkPath SkSVGContainer::onAsPath(const SkSVGRenderContext& ctx) const {
+ SkPath path;
+
+ for (int i = 0; i < fChildren.count(); ++i) {
+ const SkPath childPath = fChildren[i]->asPath(ctx);
+
+ Op(path, childPath, kUnion_SkPathOp, &path);
+ }
+
+ this->mapToParent(&path);
+ return path;
+}
diff --git a/experimental/svg/model/SkSVGContainer.h b/experimental/svg/model/SkSVGContainer.h
index 25296fcddb..6a0b00244c 100644
--- a/experimental/svg/model/SkSVGContainer.h
+++ b/experimental/svg/model/SkSVGContainer.h
@@ -22,6 +22,8 @@ protected:
void onRender(const SkSVGRenderContext&) const override;
+ SkPath onAsPath(const SkSVGRenderContext&) const override;
+
bool hasChildren() const final;
// TODO: add some sort of child iterator, and hide the container.
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp
index 2120f80e36..cea1ae69fe 100644
--- a/experimental/svg/model/SkSVGDOM.cpp
+++ b/experimental/svg/model/SkSVGDOM.cpp
@@ -11,6 +11,7 @@
#include "SkString.h"
#include "SkSVGAttributeParser.h"
#include "SkSVGCircle.h"
+#include "SkSVGClipPath.h"
#include "SkSVGDefs.h"
#include "SkSVGDOM.h"
#include "SkSVGEllipse.h"
@@ -66,6 +67,19 @@ bool SetIRIAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
return true;
}
+bool SetClipPathAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGClip clip;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseClipPath(&clip)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGClipValue(clip));
+ return true;
+}
+
+
bool SetPathDataAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
SkPath path;
@@ -263,6 +277,7 @@ struct AttrParseInfo {
};
SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
+ { "clip-path" , { SkSVGAttribute::kClipPath , SetClipPathAttribute }},
{ "cx" , { SkSVGAttribute::kCx , SetLengthAttribute }},
{ "cy" , { SkSVGAttribute::kCy , SetLengthAttribute }},
{ "d" , { SkSVGAttribute::kD , SetPathDataAttribute }},
@@ -300,6 +315,7 @@ SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
SortedDictionaryEntry<sk_sp<SkSVGNode>(*)()> gTagFactories[] = {
{ "circle" , []() -> sk_sp<SkSVGNode> { return SkSVGCircle::Make(); }},
+ { "clipPath" , []() -> sk_sp<SkSVGNode> { return SkSVGClipPath::Make(); }},
{ "defs" , []() -> sk_sp<SkSVGNode> { return SkSVGDefs::Make(); }},
{ "ellipse" , []() -> sk_sp<SkSVGNode> { return SkSVGEllipse::Make(); }},
{ "g" , []() -> sk_sp<SkSVGNode> { return SkSVGG::Make(); }},
diff --git a/experimental/svg/model/SkSVGEllipse.cpp b/experimental/svg/model/SkSVGEllipse.cpp
index 481af5c3ab..3f38b222d5 100644
--- a/experimental/svg/model/SkSVGEllipse.cpp
+++ b/experimental/svg/model/SkSVGEllipse.cpp
@@ -55,14 +55,26 @@ void SkSVGEllipse::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
}
-void SkSVGEllipse::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
- const SkPaint& paint, SkPath::FillType) const {
+SkRect SkSVGEllipse::resolve(const SkSVGLengthContext& lctx) 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);
const auto ry = lctx.resolve(fRy, SkSVGLengthContext::LengthType::kVertical);
- if (rx > 0 && ry > 0) {
- canvas->drawOval(SkRect::MakeXYWH(cx - rx, cy - ry, rx * 2, ry * 2), paint);
- }
+ return (rx > 0 && ry > 0)
+ ? SkRect::MakeXYWH(cx - rx, cy - ry, rx * 2, ry * 2)
+ : SkRect::MakeEmpty();
+}
+
+void SkSVGEllipse::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
+ const SkPaint& paint, SkPath::FillType) const {
+ canvas->drawOval(this->resolve(lctx), paint);
+}
+
+SkPath SkSVGEllipse::onAsPath(const SkSVGRenderContext& ctx) const {
+ SkPath path;
+ path.addOval(this->resolve(ctx.lengthContext()));
+ this->mapToParent(&path);
+
+ return path;
}
diff --git a/experimental/svg/model/SkSVGEllipse.h b/experimental/svg/model/SkSVGEllipse.h
index 0042b3364e..f17c1e1137 100644
--- a/experimental/svg/model/SkSVGEllipse.h
+++ b/experimental/svg/model/SkSVGEllipse.h
@@ -11,6 +11,8 @@
#include "SkSVGShape.h"
#include "SkSVGTypes.h"
+struct SkRect;
+
class SkSVGEllipse final : public SkSVGShape {
public:
virtual ~SkSVGEllipse() = default;
@@ -27,9 +29,13 @@ protected:
void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
SkPath::FillType) const override;
+ SkPath onAsPath(const SkSVGRenderContext&) const override;
+
private:
SkSVGEllipse();
+ SkRect resolve(const SkSVGLengthContext&) const;
+
SkSVGLength fCx = SkSVGLength(0);
SkSVGLength fCy = SkSVGLength(0);
SkSVGLength fRx = SkSVGLength(0);
diff --git a/experimental/svg/model/SkSVGLine.cpp b/experimental/svg/model/SkSVGLine.cpp
index 27cdd469d2..9c8f5aa02b 100644
--- a/experimental/svg/model/SkSVGLine.cpp
+++ b/experimental/svg/model/SkSVGLine.cpp
@@ -55,12 +55,30 @@ void SkSVGLine::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
}
+std::tuple<SkPoint, SkPoint> SkSVGLine::resolve(const SkSVGLengthContext& lctx) const {
+ return std::make_tuple(
+ SkPoint::Make(lctx.resolve(fX1, SkSVGLengthContext::LengthType::kHorizontal),
+ lctx.resolve(fY1, SkSVGLengthContext::LengthType::kVertical)),
+ SkPoint::Make(lctx.resolve(fX2, SkSVGLengthContext::LengthType::kHorizontal),
+ lctx.resolve(fY2, SkSVGLengthContext::LengthType::kVertical)));
+}
+
void SkSVGLine::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
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);
- const auto y2 = lctx.resolve(fY2, SkSVGLengthContext::LengthType::kVertical);
+ SkPoint p0, p1;
+ std::tie(p0, p1) = this->resolve(lctx);
+
+ canvas->drawLine(p0.x(), p0.y(), p1.x(), p1.y(), paint);
+}
+
+SkPath SkSVGLine::onAsPath(const SkSVGRenderContext& ctx) const {
+ SkPoint p0, p1;
+ std::tie(p0, p1) = this->resolve(ctx.lengthContext());
+
+ SkPath path;
+ path.moveTo(p0);
+ path.lineTo(p1);
+ this->mapToParent(&path);
- canvas->drawLine(x1, y1, x2, y2, paint);
+ return path;
}
diff --git a/experimental/svg/model/SkSVGLine.h b/experimental/svg/model/SkSVGLine.h
index 524fc2ac0e..0f15ca5ac7 100644
--- a/experimental/svg/model/SkSVGLine.h
+++ b/experimental/svg/model/SkSVGLine.h
@@ -11,6 +11,8 @@
#include "SkSVGShape.h"
#include "SkSVGTypes.h"
+struct SkPoint;
+
class SkSVGLine final : public SkSVGShape {
public:
virtual ~SkSVGLine() = default;
@@ -27,9 +29,14 @@ protected:
void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
SkPath::FillType) const override;
+ SkPath onAsPath(const SkSVGRenderContext&) const override;
+
private:
SkSVGLine();
+ // resolve and return the two endpoints
+ std::tuple<SkPoint, SkPoint> resolve(const SkSVGLengthContext&) const;
+
SkSVGLength fX1 = SkSVGLength(0);
SkSVGLength fY1 = SkSVGLength(0);
SkSVGLength fX2 = SkSVGLength(0);
diff --git a/experimental/svg/model/SkSVGNode.cpp b/experimental/svg/model/SkSVGNode.cpp
index a5c8147554..ec452ec9c6 100644
--- a/experimental/svg/model/SkSVGNode.cpp
+++ b/experimental/svg/model/SkSVGNode.cpp
@@ -30,6 +30,11 @@ bool SkSVGNode::asPaint(const SkSVGRenderContext& ctx, SkPaint* paint) const {
return this->onPrepareToRender(&localContext) && this->onAsPaint(localContext, paint);
}
+SkPath SkSVGNode::asPath(const SkSVGRenderContext& ctx) const {
+ SkSVGRenderContext localContext(ctx);
+ return this->onPrepareToRender(&localContext) ? this->onAsPath(localContext) : SkPath();
+}
+
bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
ctx->applyPresentationAttributes(fPresentationAttributes,
this->hasChildren() ? 0 : SkSVGRenderContext::kLeaf);
@@ -40,6 +45,10 @@ void SkSVGNode::setAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
this->onSetAttribute(attr, v);
}
+void SkSVGNode::setClipPath(const SkSVGClip& clip) {
+ fPresentationAttributes.fClipPath.set(clip);
+}
+
void SkSVGNode::setFill(const SkSVGPaint& svgPaint) {
fPresentationAttributes.fFill.set(svgPaint);
}
@@ -73,6 +82,11 @@ void SkSVGNode::setStrokeWidth(const SkSVGLength& strokeWidth) {
void SkSVGNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
switch (attr) {
+ case SkSVGAttribute::kClipPath:
+ if (const SkSVGClipValue* clip = v.as<SkSVGClipValue>()) {
+ this->setClipPath(*clip);
+ }
+ break;
case SkSVGAttribute::kFill:
if (const SkSVGPaintValue* paint = v.as<SkSVGPaintValue>()) {
this->setFill(*paint);
diff --git a/experimental/svg/model/SkSVGNode.h b/experimental/svg/model/SkSVGNode.h
index 1e092a4d87..385b1584b8 100644
--- a/experimental/svg/model/SkSVGNode.h
+++ b/experimental/svg/model/SkSVGNode.h
@@ -14,11 +14,13 @@
class SkCanvas;
class SkMatrix;
class SkPaint;
+class SkPath;
class SkSVGRenderContext;
class SkSVGValue;
enum class SkSVGTag {
kCircle,
+ kClipPath,
kDefs,
kEllipse,
kG,
@@ -42,9 +44,11 @@ public:
void render(const SkSVGRenderContext&) const;
bool asPaint(const SkSVGRenderContext&, SkPaint*) const;
+ SkPath asPath(const SkSVGRenderContext&) const;
void setAttribute(SkSVGAttribute, const SkSVGValue&);
+ void setClipPath(const SkSVGClip&);
void setFill(const SkSVGPaint&);
void setFillOpacity(const SkSVGNumberType&);
void setFillRule(const SkSVGFillRule&);
@@ -68,6 +72,8 @@ protected:
virtual bool onAsPaint(const SkSVGRenderContext&, SkPaint*) const { return false; }
+ virtual SkPath onAsPath(const SkSVGRenderContext&) const = 0;
+
virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
virtual bool hasChildren() const { return false; }
diff --git a/experimental/svg/model/SkSVGPath.cpp b/experimental/svg/model/SkSVGPath.cpp
index dd248237f1..7568744035 100644
--- a/experimental/svg/model/SkSVGPath.cpp
+++ b/experimental/svg/model/SkSVGPath.cpp
@@ -31,3 +31,12 @@ void SkSVGPath::onDraw(SkCanvas* canvas, const SkSVGLengthContext&, const SkPain
fPath.setFillType(fillType);
canvas->drawPath(fPath, paint);
}
+
+SkPath SkSVGPath::onAsPath(const SkSVGRenderContext& ctx) const {
+ // the computed fillType follows inheritance rules and needs to be applied at draw time.
+ fPath.setFillType(FillRuleToFillType(*ctx.presentationContext().fInherited.fFillRule.get()));
+
+ SkPath path = fPath;
+ this->mapToParent(&path);
+ return path;
+}
diff --git a/experimental/svg/model/SkSVGPath.h b/experimental/svg/model/SkSVGPath.h
index 8297a8d557..8b1f2e98f8 100644
--- a/experimental/svg/model/SkSVGPath.h
+++ b/experimental/svg/model/SkSVGPath.h
@@ -24,6 +24,8 @@ protected:
void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
SkPath::FillType) const override;
+ SkPath onAsPath(const SkSVGRenderContext&) const override;
+
private:
SkSVGPath();
diff --git a/experimental/svg/model/SkSVGPoly.cpp b/experimental/svg/model/SkSVGPoly.cpp
index 826ca2457e..479638e93f 100644
--- a/experimental/svg/model/SkSVGPoly.cpp
+++ b/experimental/svg/model/SkSVGPoly.cpp
@@ -38,3 +38,12 @@ void SkSVGPoly::onDraw(SkCanvas* canvas, const SkSVGLengthContext&, const SkPain
fPath.setFillType(fillType);
canvas->drawPath(fPath, paint);
}
+
+SkPath SkSVGPoly::onAsPath(const SkSVGRenderContext& ctx) const {
+ // the computed fillType follows inheritance rules and needs to be applied at draw time.
+ fPath.setFillType(FillRuleToFillType(*ctx.presentationContext().fInherited.fFillRule.get()));
+
+ SkPath path = fPath;
+ this->mapToParent(&path);
+ return path;
+}
diff --git a/experimental/svg/model/SkSVGPoly.h b/experimental/svg/model/SkSVGPoly.h
index f75d3626cc..90fb354d35 100644
--- a/experimental/svg/model/SkSVGPoly.h
+++ b/experimental/svg/model/SkSVGPoly.h
@@ -32,6 +32,8 @@ protected:
void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
SkPath::FillType) const override;
+ SkPath onAsPath(const SkSVGRenderContext&) const override;
+
private:
SkSVGPoly(SkSVGTag);
diff --git a/experimental/svg/model/SkSVGRect.cpp b/experimental/svg/model/SkSVGRect.cpp
index 1afd9957c6..fe68d62297 100644
--- a/experimental/svg/model/SkSVGRect.cpp
+++ b/experimental/svg/model/SkSVGRect.cpp
@@ -74,15 +74,24 @@ void SkSVGRect::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
}
}
-void SkSVGRect::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
- const SkPaint& paint, SkPath::FillType) const {
+SkRRect SkSVGRect::resolve(const SkSVGLengthContext& lctx) 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);
- if (rx || ry) {
- canvas->drawRRect(SkRRect::MakeRectXY(rect, rx, ry), paint);
- } else {
- canvas->drawRect(rect, paint);
- }
+ return SkRRect::MakeRectXY(rect, rx ,ry);
+}
+
+void SkSVGRect::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
+ const SkPaint& paint, SkPath::FillType) const {
+ canvas->drawRRect(this->resolve(lctx), paint);
+}
+
+SkPath SkSVGRect::onAsPath(const SkSVGRenderContext& ctx) const {
+ SkPath path;
+ path.addRRect(this->resolve(ctx.lengthContext()));
+
+ this->mapToParent(&path);
+
+ return path;
}
diff --git a/experimental/svg/model/SkSVGRect.h b/experimental/svg/model/SkSVGRect.h
index affa65f610..a0c07a1957 100644
--- a/experimental/svg/model/SkSVGRect.h
+++ b/experimental/svg/model/SkSVGRect.h
@@ -11,6 +11,8 @@
#include "SkSVGShape.h"
#include "SkSVGTypes.h"
+class SkRRect;
+
class SkSVGRect final : public SkSVGShape {
public:
virtual ~SkSVGRect() = default;
@@ -29,9 +31,13 @@ protected:
void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&,
SkPath::FillType) const override;
+ SkPath onAsPath(const SkSVGRenderContext&) const override;
+
private:
SkSVGRect();
+ SkRRect resolve(const SkSVGLengthContext&) const;
+
SkSVGLength fX = SkSVGLength(0);
SkSVGLength fY = SkSVGLength(0);
SkSVGLength fWidth = SkSVGLength(0);
diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp
index fd0262319a..d8307a05c0 100644
--- a/experimental/svg/model/SkSVGRenderContext.cpp
+++ b/experimental/svg/model/SkSVGRenderContext.cpp
@@ -280,6 +280,10 @@ void SkSVGRenderContext::applyPresentationAttributes(const SkSVGPresentationAttr
if (auto* opacity = attrs.fOpacity.getMaybeNull()) {
this->applyOpacity(opacity->value(), flags);
}
+
+ if (auto* clip = attrs.fClipPath.getMaybeNull()) {
+ this->applyClip(*clip);
+ }
}
void SkSVGRenderContext::applyOpacity(SkScalar opacity, uint32_t flags) {
@@ -312,6 +316,26 @@ void SkSVGRenderContext::applyOpacity(SkScalar opacity, uint32_t flags) {
}
}
+void SkSVGRenderContext::applyClip(const SkSVGClip& clip) {
+ if (clip.type() != SkSVGClip::Type::kIRI) {
+ return;
+ }
+
+ const SkSVGNode* clipNode = this->findNodeById(clip.iri());
+ if (!clipNode || clipNode->tag() != SkSVGTag::kClipPath) {
+ return;
+ }
+
+ const SkPath clipPath = clipNode->asPath(*this);
+
+ // Only save if needed
+ if (fCanvas->getSaveCount() == fCanvasSaveCount) {
+ fCanvas->save();
+ }
+
+ fCanvas->clipPath(clipPath, true);
+}
+
const SkPaint* SkSVGRenderContext::fillPaint() const {
const SkSVGPaint::Type paintType = fPresentationContext->fInherited.fFill.get()->type();
return paintType != SkSVGPaint::Type::kNone ? &fPresentationContext->fFillPaint : nullptr;
diff --git a/experimental/svg/model/SkSVGRenderContext.h b/experimental/svg/model/SkSVGRenderContext.h
index 9d2fb3a621..ab046cd290 100644
--- a/experimental/svg/model/SkSVGRenderContext.h
+++ b/experimental/svg/model/SkSVGRenderContext.h
@@ -86,6 +86,7 @@ private:
SkSVGRenderContext& operator=(const SkSVGRenderContext&) = delete;
void applyOpacity(SkScalar opacity, uint32_t flags);
+ void applyClip(const SkSVGClip&);
const SkSVGIDMapper& fIDMapper;
SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext;
diff --git a/experimental/svg/model/SkSVGTransformableNode.cpp b/experimental/svg/model/SkSVGTransformableNode.cpp
index 8a095ac62a..b2ad0b1ab9 100644
--- a/experimental/svg/model/SkSVGTransformableNode.cpp
+++ b/experimental/svg/model/SkSVGTransformableNode.cpp
@@ -36,3 +36,16 @@ void SkSVGTransformableNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValu
break;
}
}
+
+void SkSVGTransformableNode::mapToParent(SkPath* path) const {
+ if (fTransform.value().isIdentity()) {
+ return;
+ }
+
+ SkMatrix inv;
+ if (!fTransform.value().invert(&inv)) {
+ return;
+ }
+
+ path->transform(inv);
+}
diff --git a/experimental/svg/model/SkSVGTransformableNode.h b/experimental/svg/model/SkSVGTransformableNode.h
index 05644ac973..ad217a92f9 100644
--- a/experimental/svg/model/SkSVGTransformableNode.h
+++ b/experimental/svg/model/SkSVGTransformableNode.h
@@ -24,6 +24,8 @@ protected:
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
+ void mapToParent(SkPath*) const;
+
private:
// FIXME: should be sparse
SkSVGTransformType fTransform;
diff --git a/experimental/svg/model/SkSVGTypes.h b/experimental/svg/model/SkSVGTypes.h
index d5d2b7146f..42a09b93b5 100644
--- a/experimental/svg/model/SkSVGTypes.h
+++ b/experimental/svg/model/SkSVGTypes.h
@@ -119,6 +119,34 @@ private:
SkString fIRI;
};
+class SkSVGClip {
+public:
+ enum class Type {
+ kNone,
+ kInherit,
+ kIRI,
+ };
+
+ SkSVGClip() : fType(Type::kNone) {}
+ explicit SkSVGClip(Type t) : fType(t) {}
+ explicit SkSVGClip(const SkString& iri) : fType(Type::kIRI), fIRI(iri) {}
+
+ SkSVGClip(const SkSVGClip&) = default;
+ SkSVGClip& operator=(const SkSVGClip&) = default;
+
+ bool operator==(const SkSVGClip& other) const {
+ return fType == other.fType && fIRI == other.fIRI;
+ }
+ bool operator!=(const SkSVGClip& other) const { return !(*this == other); }
+
+ Type type() const { return fType; }
+ const SkString& iri() const { SkASSERT(fType == Type::kIRI); return fIRI; }
+
+private:
+ Type fType;
+ SkString fIRI;
+};
+
class SkSVGLineCap {
public:
enum class Type {
diff --git a/experimental/svg/model/SkSVGValue.h b/experimental/svg/model/SkSVGValue.h
index 9f3095c918..8e58b0672a 100644
--- a/experimental/svg/model/SkSVGValue.h
+++ b/experimental/svg/model/SkSVGValue.h
@@ -17,6 +17,7 @@
class SkSVGValue : public SkNoncopyable {
public:
enum class Type {
+ kClip,
kColor,
kFillRule,
kLength,
@@ -70,6 +71,7 @@ private:
typedef SkSVGValue INHERITED;
};
+using SkSVGClipValue = SkSVGWrapperValue<SkSVGClip , SkSVGValue::Type::kClip >;
using SkSVGColorValue = SkSVGWrapperValue<SkSVGColorType , SkSVGValue::Type::kColor >;
using SkSVGFillRuleValue = SkSVGWrapperValue<SkSVGFillRule , SkSVGValue::Type::kFillRule >;
using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength , SkSVGValue::Type::kLength >;