aboutsummaryrefslogtreecommitdiffhomepage
path: root/experimental/svg
diff options
context:
space:
mode:
authorGravatar fmalita <fmalita@chromium.org>2016-08-08 11:38:55 -0700
committerGravatar Commit bot <commit-bot@chromium.org>2016-08-08 11:38:55 -0700
commit397a517d1a5774653fcdd08172f9a6b5eea67621 (patch)
treeab9c9aaa4121a8033a29f259401bcecf7d178203 /experimental/svg
parentf621ff49a288978c272d5ae069a6a1c04c74642b (diff)
[SVGDom] Add viewBox support
The main feature is <svg> viewBox and proper viewport support, but the CL touches a few other things: * refactor SkSVGRenderContext to auto-restore canvas state, and split the presentation bits into a separate CoW SkSVGPresentationContext * introduce SkSVGNode::onPrepareToRender(), as a way for nodes to push their custom state before the actual onRender() call (instead of relying on non-virtual SkSVGNode to know about all possible state bits) * add a "Type" suffix to SVG types, to disambiguate (e.g. SkSVGRectType vs. SkSVGRect) R=robertphillips@google.com,stephana@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2222793002 Review-Url: https://codereview.chromium.org/2222793002
Diffstat (limited to 'experimental/svg')
-rw-r--r--experimental/svg/model/SkSVGAttribute.cpp10
-rw-r--r--experimental/svg/model/SkSVGAttribute.h15
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.cpp27
-rw-r--r--experimental/svg/model/SkSVGAttributeParser.h5
-rw-r--r--experimental/svg/model/SkSVGContainer.cpp4
-rw-r--r--experimental/svg/model/SkSVGContainer.h2
-rw-r--r--experimental/svg/model/SkSVGDOM.cpp21
-rw-r--r--experimental/svg/model/SkSVGNode.cpp23
-rw-r--r--experimental/svg/model/SkSVGNode.h14
-rw-r--r--experimental/svg/model/SkSVGRect.cpp8
-rw-r--r--experimental/svg/model/SkSVGRenderContext.cpp51
-rw-r--r--experimental/svg/model/SkSVGRenderContext.h57
-rw-r--r--experimental/svg/model/SkSVGSVG.cpp43
-rw-r--r--experimental/svg/model/SkSVGSVG.h6
-rw-r--r--experimental/svg/model/SkSVGShape.cpp10
-rw-r--r--experimental/svg/model/SkSVGShape.h2
-rw-r--r--experimental/svg/model/SkSVGTransformableNode.cpp12
-rw-r--r--experimental/svg/model/SkSVGTransformableNode.h4
-rw-r--r--experimental/svg/model/SkSVGTypes.h34
-rw-r--r--experimental/svg/model/SkSVGValue.h22
20 files changed, 265 insertions, 105 deletions
diff --git a/experimental/svg/model/SkSVGAttribute.cpp b/experimental/svg/model/SkSVGAttribute.cpp
index 79c355176f..2f1cace773 100644
--- a/experimental/svg/model/SkSVGAttribute.cpp
+++ b/experimental/svg/model/SkSVGAttribute.cpp
@@ -12,23 +12,23 @@ SkSVGPresentationAttributes::SkSVGPresentationAttributes()
: fFillIsSet(false)
, fStrokeIsSet(false) { }
-void SkSVGPresentationAttributes::setFill(const SkSVGColor& c) {
+void SkSVGPresentationAttributes::setFill(const SkSVGColorType& c) {
fFill = c;
fFillIsSet = true;
}
-void SkSVGPresentationAttributes::setStroke(const SkSVGColor& c) {
+void SkSVGPresentationAttributes::setStroke(const SkSVGColorType& c) {
fStroke = c;
fStrokeIsSet = true;
}
-void SkSVGPresentationAttributes::applyTo(SkTCopyOnFirstWrite<SkSVGRenderContext>& ctx) const {
+void SkSVGPresentationAttributes::applyTo(SkSVGRenderContext* ctx) const {
if (fFillIsSet) {
- ctx.writable()->setFillColor(fFill);
+ ctx->writablePresentationContext()->setFillColor(fFill);
}
if (fStrokeIsSet) {
- ctx.writable()->setStrokeColor(fStroke);
+ ctx->writablePresentationContext()->setStrokeColor(fStroke);
}
}
diff --git a/experimental/svg/model/SkSVGAttribute.h b/experimental/svg/model/SkSVGAttribute.h
index 64465b13c9..d05737b69f 100644
--- a/experimental/svg/model/SkSVGAttribute.h
+++ b/experimental/svg/model/SkSVGAttribute.h
@@ -11,12 +11,15 @@
#include "SkSVGTypes.h"
#include "SkTLazy.h"
+class SkSVGRenderContext;
+
enum class SkSVGAttribute {
kD,
kFill,
kHeight,
kStroke,
kTransform,
+ kViewBox,
kWidth,
kX,
kY,
@@ -24,21 +27,19 @@ enum class SkSVGAttribute {
kUnknown,
};
-class SkSVGRenderContext;
-
class SkSVGPresentationAttributes {
public:
SkSVGPresentationAttributes();
- void setFill(const SkSVGColor&);
- void setStroke(const SkSVGColor&);
+ void setFill(const SkSVGColorType&);
+ void setStroke(const SkSVGColorType&);
- void applyTo(SkTCopyOnFirstWrite<SkSVGRenderContext>&) const;
+ void applyTo(SkSVGRenderContext*) const;
private:
// Color only for now.
- SkSVGColor fFill;
- SkSVGColor fStroke;
+ SkSVGColorType fFill;
+ SkSVGColorType fStroke;
unsigned fFillIsSet : 1;
unsigned fStrokeIsSet : 1;
diff --git a/experimental/svg/model/SkSVGAttributeParser.cpp b/experimental/svg/model/SkSVGAttributeParser.cpp
index 75e5d12f38..62ca4c8ab2 100644
--- a/experimental/svg/model/SkSVGAttributeParser.cpp
+++ b/experimental/svg/model/SkSVGAttributeParser.cpp
@@ -149,12 +149,12 @@ bool SkSVGAttributeParser::parseHexColorToken(SkColor* c) {
}
// https://www.w3.org/TR/SVG/types.html#DataTypeColor
-bool SkSVGAttributeParser::parseColor(SkSVGColor* color) {
+bool SkSVGAttributeParser::parseColor(SkSVGColorType* color) {
SkColor c;
// TODO: rgb(...)
if (this->parseHexColorToken(&c) || this->parseNamedColorToken(&c)) {
- *color = SkSVGColor(c);
+ *color = SkSVGColorType(c);
return true;
}
@@ -162,13 +162,13 @@ bool SkSVGAttributeParser::parseColor(SkSVGColor* color) {
}
// https://www.w3.org/TR/SVG/types.html#DataTypeNumber
-bool SkSVGAttributeParser::parseNumber(SkSVGNumber* number) {
+bool SkSVGAttributeParser::parseNumber(SkSVGNumberType* number) {
// consume WS
this->parseWSToken();
SkScalar s;
if (this->parseScalarToken(&s)) {
- *number = SkSVGNumber(s);
+ *number = SkSVGNumberType(s);
// consume trailing separators
this->parseSepToken();
return true;
@@ -192,3 +192,22 @@ bool SkSVGAttributeParser::parseLength(SkSVGLength* length) {
return false;
}
+
+// https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
+bool SkSVGAttributeParser::parseViewBox(SkSVGViewBoxType* vb) {
+ SkScalar x, y, w, h;
+ this->parseWSToken();
+
+ bool parsedValue = false;
+ if (this->parseScalarToken(&x) && this->parseSepToken() &&
+ this->parseScalarToken(&y) && this->parseSepToken() &&
+ this->parseScalarToken(&w) && this->parseSepToken() &&
+ this->parseScalarToken(&h)) {
+
+ *vb = SkSVGViewBoxType(SkRect::MakeXYWH(x, y, w, h));
+ parsedValue = true;
+ // consume trailing whitespace
+ this->parseWSToken();
+ }
+ return parsedValue && this->parseEOSToken();
+}
diff --git a/experimental/svg/model/SkSVGAttributeParser.h b/experimental/svg/model/SkSVGAttributeParser.h
index aef0286504..cd50479fee 100644
--- a/experimental/svg/model/SkSVGAttributeParser.h
+++ b/experimental/svg/model/SkSVGAttributeParser.h
@@ -14,9 +14,10 @@ class SkSVGAttributeParser : public SkNoncopyable {
public:
SkSVGAttributeParser(const char[]);
- bool parseColor(SkSVGColor*);
- bool parseNumber(SkSVGNumber*);
+ bool parseColor(SkSVGColorType*);
+ bool parseNumber(SkSVGNumberType*);
bool parseLength(SkSVGLength*);
+ bool parseViewBox(SkSVGViewBoxType*);
private:
// Stack-only
diff --git a/experimental/svg/model/SkSVGContainer.cpp b/experimental/svg/model/SkSVGContainer.cpp
index f8667975bd..4f91b30bab 100644
--- a/experimental/svg/model/SkSVGContainer.cpp
+++ b/experimental/svg/model/SkSVGContainer.cpp
@@ -14,8 +14,8 @@ void SkSVGContainer::appendChild(sk_sp<SkSVGNode> node) {
fChildren.push_back(std::move(node));
}
-void SkSVGContainer::onRender(SkCanvas* canvas, const SkSVGRenderContext& ctx) const {
+void SkSVGContainer::onRender(const SkSVGRenderContext& ctx) const {
for (int i = 0; i < fChildren.count(); ++i) {
- fChildren[i]->render(canvas, ctx);
+ fChildren[i]->render(ctx);
}
}
diff --git a/experimental/svg/model/SkSVGContainer.h b/experimental/svg/model/SkSVGContainer.h
index 27c7944da7..9a3fd621ab 100644
--- a/experimental/svg/model/SkSVGContainer.h
+++ b/experimental/svg/model/SkSVGContainer.h
@@ -20,7 +20,7 @@ public:
protected:
SkSVGContainer(SkSVGTag);
- void onRender(SkCanvas*, const SkSVGRenderContext&) const override;
+ void onRender(const SkSVGRenderContext&) const override;
private:
SkSTArray<1, sk_sp<SkSVGNode>, true> fChildren;
diff --git a/experimental/svg/model/SkSVGDOM.cpp b/experimental/svg/model/SkSVGDOM.cpp
index df589230e0..13d67b9cfe 100644
--- a/experimental/svg/model/SkSVGDOM.cpp
+++ b/experimental/svg/model/SkSVGDOM.cpp
@@ -73,7 +73,7 @@ SkMatrix ParseTransform(const char* str) {
bool SetPaintAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
const char* stringValue) {
- SkSVGColor color;
+ SkSVGColorType color;
SkSVGAttributeParser parser(stringValue);
if (!parser.parseColor(&color)) {
return false;
@@ -112,6 +112,18 @@ bool SetLengthAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
return true;
}
+bool SetViewBoxAttribute(const sk_sp<SkSVGNode>& node, SkSVGAttribute attr,
+ const char* stringValue) {
+ SkSVGViewBoxType viewBox;
+ SkSVGAttributeParser parser(stringValue);
+ if (!parser.parseViewBox(&viewBox)) {
+ return false;
+ }
+
+ node->setAttribute(attr, SkSVGViewBoxValue(viewBox));
+ return true;
+}
+
// Breaks a "foo: bar; baz: ..." string into key:value pairs.
class StyleIterator {
public:
@@ -184,6 +196,7 @@ SortedDictionaryEntry<AttrParseInfo> gAttributeParseInfo[] = {
{ "stroke" , { SkSVGAttribute::kStroke , SetPaintAttribute }},
{ "style" , { SkSVGAttribute::kUnknown , SetStyleAttributes }},
{ "transform", { SkSVGAttribute::kTransform, SetTransformAttribute }},
+ { "viewBox" , { SkSVGAttribute::kViewBox , SetViewBoxAttribute }},
{ "width" , { SkSVGAttribute::kWidth , SetLengthAttribute }},
{ "x" , { SkSVGAttribute::kX , SetLengthAttribute }},
{ "y" , { SkSVGAttribute::kY , SetLengthAttribute }},
@@ -292,8 +305,10 @@ sk_sp<SkSVGDOM> SkSVGDOM::MakeFromStream(SkStream& svgStream, const SkSize& cont
void SkSVGDOM::render(SkCanvas* canvas) const {
if (fRoot) {
- SkSVGRenderContext ctx(fContainerSize);
- fRoot->render(canvas, ctx);
+ SkSVGRenderContext ctx(canvas,
+ SkSVGLengthContext(fContainerSize),
+ SkSVGPresentationContext());
+ fRoot->render(ctx);
}
}
diff --git a/experimental/svg/model/SkSVGNode.cpp b/experimental/svg/model/SkSVGNode.cpp
index eb82834f38..34c6e17d61 100644
--- a/experimental/svg/model/SkSVGNode.cpp
+++ b/experimental/svg/model/SkSVGNode.cpp
@@ -16,18 +16,17 @@ SkSVGNode::SkSVGNode(SkSVGTag t) : fTag(t) { }
SkSVGNode::~SkSVGNode() { }
-void SkSVGNode::render(SkCanvas* canvas, const SkSVGRenderContext& ctx) const {
- SkTCopyOnFirstWrite<SkSVGRenderContext> localContext(ctx);
- fPresentationAttributes.applyTo(localContext);
-
- SkAutoCanvasRestore acr(canvas, false);
- const SkMatrix& m = this->onLocalMatrix();
- if (!m.isIdentity()) {
- canvas->save();
- canvas->concat(m);
+void SkSVGNode::render(const SkSVGRenderContext& ctx) const {
+ SkSVGRenderContext localContext(ctx);
+
+ if (this->onPrepareToRender(&localContext)) {
+ this->onRender(localContext);
}
+}
- this->onRender(canvas, *localContext);
+bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
+ fPresentationAttributes.applyTo(ctx);
+ return true;
}
void SkSVGNode::setAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
@@ -51,7 +50,3 @@ void SkSVGNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
break;
}
}
-
-const SkMatrix& SkSVGNode::onLocalMatrix() const {
- return SkMatrix::I();
-}
diff --git a/experimental/svg/model/SkSVGNode.h b/experimental/svg/model/SkSVGNode.h
index 168b03c73b..38a17d8633 100644
--- a/experimental/svg/model/SkSVGNode.h
+++ b/experimental/svg/model/SkSVGNode.h
@@ -31,18 +31,24 @@ public:
virtual void appendChild(sk_sp<SkSVGNode>) = 0;
- void render(SkCanvas*, const SkSVGRenderContext&) const;
+ void render(const SkSVGRenderContext&) const;
void setAttribute(SkSVGAttribute, const SkSVGValue&);
protected:
SkSVGNode(SkSVGTag);
- virtual void onRender(SkCanvas*, const SkSVGRenderContext&) const = 0;
+ // Called before onRender(), to apply local attributes to the context. Unlike onRender(),
+ // onPrepareToRender() bubbles up the inheritance chain: overriders should always call
+ // INHERITED::onPrepareToRender(), unless they intend to short-circuit rendering
+ // (return false).
+ // Implementations are expected to return true if rendering is to continue, or false if
+ // the node/subtree rendering is disabled.
+ virtual bool onPrepareToRender(SkSVGRenderContext*) const;
- virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
+ virtual void onRender(const SkSVGRenderContext&) const = 0;
- virtual const SkMatrix& onLocalMatrix() const;
+ virtual void onSetAttribute(SkSVGAttribute, const SkSVGValue&);
private:
SkSVGTag fTag;
diff --git a/experimental/svg/model/SkSVGRect.cpp b/experimental/svg/model/SkSVGRect.cpp
index 288fc48258..b65c2b9974 100644
--- a/experimental/svg/model/SkSVGRect.cpp
+++ b/experimental/svg/model/SkSVGRect.cpp
@@ -58,11 +58,5 @@ void SkSVGRect::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
void SkSVGRect::onDraw(SkCanvas* canvas, const SkSVGLengthContext& lctx,
const SkPaint& paint) const {
- const SkRect r = SkRect::MakeXYWH(
- lctx.resolve(fX, SkSVGLengthContext::LengthType::kHorizontal),
- lctx.resolve(fY, SkSVGLengthContext::LengthType::kVertical),
- lctx.resolve(fWidth, SkSVGLengthContext::LengthType::kHorizontal),
- lctx.resolve(fHeight, SkSVGLengthContext::LengthType::kVertical));
-
- canvas->drawRect(r, paint);
+ canvas->drawRect(lctx.resolveRect(fX, fY, fWidth, fHeight), paint);
}
diff --git a/experimental/svg/model/SkSVGRenderContext.cpp b/experimental/svg/model/SkSVGRenderContext.cpp
index 38498d36c8..e902d4ecf3 100644
--- a/experimental/svg/model/SkSVGRenderContext.cpp
+++ b/experimental/svg/model/SkSVGRenderContext.cpp
@@ -5,6 +5,7 @@
* found in the LICENSE file.
*/
+#include "SkCanvas.h"
#include "SkSVGRenderContext.h"
#include "SkSVGTypes.h"
@@ -42,10 +43,27 @@ SkScalar SkSVGLengthContext::resolve(const SkSVGLength& l, LengthType t) const {
return 0;
}
-SkSVGRenderContext::SkSVGRenderContext(const SkSize& initialViewport)
- : fLengthContext(initialViewport) {}
+SkRect SkSVGLengthContext::resolveRect(const SkSVGLength& x, const SkSVGLength& y,
+ const SkSVGLength& w, const SkSVGLength& h) const {
+ return SkRect::MakeXYWH(
+ this->resolve(x, SkSVGLengthContext::LengthType::kHorizontal),
+ this->resolve(y, SkSVGLengthContext::LengthType::kVertical),
+ this->resolve(w, SkSVGLengthContext::LengthType::kHorizontal),
+ this->resolve(h, SkSVGLengthContext::LengthType::kVertical));
+}
+
+SkSVGPresentationContext::SkSVGPresentationContext() {}
+
+SkSVGPresentationContext::SkSVGPresentationContext(const SkSVGPresentationContext& o) {
+ this->initFrom(o);
+}
+
+SkSVGPresentationContext& SkSVGPresentationContext::operator=(const SkSVGPresentationContext& o) {
+ this->initFrom(o);
+ return *this;
+}
-SkSVGRenderContext& SkSVGRenderContext::operator=(const SkSVGRenderContext& other) {
+void SkSVGPresentationContext::initFrom(const SkSVGPresentationContext& other) {
if (other.fFill.isValid()) {
fFill.set(*other.fFill.get());
} else {
@@ -57,11 +75,9 @@ SkSVGRenderContext& SkSVGRenderContext::operator=(const SkSVGRenderContext& othe
} else {
fStroke.reset();
}
-
- return *this;
}
-SkPaint& SkSVGRenderContext::ensureFill() {
+SkPaint& SkSVGPresentationContext::ensureFill() {
if (!fFill.isValid()) {
fFill.init();
fFill.get()->setStyle(SkPaint::kFill_Style);
@@ -70,7 +86,7 @@ SkPaint& SkSVGRenderContext::ensureFill() {
return *fFill.get();
}
-SkPaint& SkSVGRenderContext::ensureStroke() {
+SkPaint& SkSVGPresentationContext::ensureStroke() {
if (!fStroke.isValid()) {
fStroke.init();
fStroke.get()->setStyle(SkPaint::kStroke_Style);
@@ -79,10 +95,27 @@ SkPaint& SkSVGRenderContext::ensureStroke() {
return *fStroke.get();
}
-void SkSVGRenderContext::setFillColor(SkColor color) {
+void SkSVGPresentationContext::setFillColor(SkColor color) {
this->ensureFill().setColor(color);
}
-void SkSVGRenderContext::setStrokeColor(SkColor color) {
+void SkSVGPresentationContext::setStrokeColor(SkColor color) {
this->ensureStroke().setColor(color);
}
+
+SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas,
+ const SkSVGLengthContext& lctx,
+ const SkSVGPresentationContext& pctx)
+ : fLengthContext(lctx)
+ , fPresentationContext(pctx)
+ , fCanvas(canvas)
+ , fCanvasSaveCount(canvas->getSaveCount()) {}
+
+SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other)
+ : SkSVGRenderContext(other.canvas(),
+ other.lengthContext(),
+ other.presentationContext()) {}
+
+SkSVGRenderContext::~SkSVGRenderContext() {
+ fCanvas->restoreToCount(fCanvasSaveCount);
+}
diff --git a/experimental/svg/model/SkSVGRenderContext.h b/experimental/svg/model/SkSVGRenderContext.h
index 50a6d59e5e..47886d7cb0 100644
--- a/experimental/svg/model/SkSVGRenderContext.h
+++ b/experimental/svg/model/SkSVGRenderContext.h
@@ -8,11 +8,13 @@
#ifndef SkSVGRenderContext_DEFINED
#define SkSVGRenderContext_DEFINED
-#include "SkSize.h"
#include "SkPaint.h"
+#include "SkRect.h"
+#include "SkSize.h"
#include "SkTLazy.h"
+#include "SkTypes.h"
-class SkPaint;
+class SkCanvas;
class SkSVGLength;
class SkSVGLengthContext {
@@ -25,21 +27,22 @@ public:
kOther,
};
+ const SkSize& viewPort() const { return fViewport; }
void setViewPort(const SkSize& viewport) { fViewport = viewport; }
SkScalar resolve(const SkSVGLength&, LengthType) const;
+ SkRect resolveRect(const SkSVGLength& x, const SkSVGLength& y,
+ const SkSVGLength& w, const SkSVGLength& h) const;
private:
SkSize fViewport;
};
-class SkSVGRenderContext {
+class SkSVGPresentationContext {
public:
- explicit SkSVGRenderContext(const SkSize& initialViewport);
- SkSVGRenderContext(const SkSVGRenderContext&) = default;
- SkSVGRenderContext& operator=(const SkSVGRenderContext&);
-
- const SkSVGLengthContext& lengthContext() const { return fLengthContext; }
+ SkSVGPresentationContext();
+ SkSVGPresentationContext(const SkSVGPresentationContext&);
+ SkSVGPresentationContext& operator=(const SkSVGPresentationContext&);
const SkPaint* fillPaint() const { return fFill.getMaybeNull(); }
const SkPaint* strokePaint() const { return fStroke.getMaybeNull(); }
@@ -48,12 +51,44 @@ public:
void setStrokeColor(SkColor);
private:
+ void initFrom(const SkSVGPresentationContext&);
+
SkPaint& ensureFill();
SkPaint& ensureStroke();
- SkSVGLengthContext fLengthContext;
- SkTLazy<SkPaint> fFill;
- SkTLazy<SkPaint> fStroke;
+ // TODO: convert to regular SkPaints and track explicit attribute values instead.
+ SkTLazy<SkPaint> fFill;
+ SkTLazy<SkPaint> fStroke;
+};
+
+class SkSVGRenderContext {
+public:
+ SkSVGRenderContext(SkCanvas*, const SkSVGLengthContext&, const SkSVGPresentationContext&);
+ SkSVGRenderContext(const SkSVGRenderContext&);
+ ~SkSVGRenderContext();
+
+ const SkSVGLengthContext& lengthContext() const { return *fLengthContext; }
+ SkSVGLengthContext* writableLengthContext() { return fLengthContext.writable(); }
+
+ const SkSVGPresentationContext& presentationContext() const { return *fPresentationContext; }
+ SkSVGPresentationContext* writablePresentationContext() {
+ return fPresentationContext.writable();
+ }
+
+ SkCanvas* canvas() const { return fCanvas; }
+
+private:
+ // Stack-only
+ void* operator new(size_t) = delete;
+ void* operator new(size_t, void*) = delete;
+ SkSVGRenderContext& operator=(const SkSVGRenderContext&) = delete;
+
+ SkTCopyOnFirstWrite<SkSVGLengthContext> fLengthContext;
+ SkTCopyOnFirstWrite<SkSVGPresentationContext> fPresentationContext;
+ SkCanvas* fCanvas;
+ // The save count on 'fCanvas' at construction time.
+ // A restoreToCount() will be issued on destruction.
+ int fCanvasSaveCount;
};
#endif // SkSVGRenderContext_DEFINED
diff --git a/experimental/svg/model/SkSVGSVG.cpp b/experimental/svg/model/SkSVGSVG.cpp
index 42bd280a5e..13f18043c0 100644
--- a/experimental/svg/model/SkSVGSVG.cpp
+++ b/experimental/svg/model/SkSVGSVG.cpp
@@ -5,11 +5,45 @@
* found in the LICENSE file.
*/
+#include "SkCanvas.h"
+#include "SkSVGRenderContext.h"
#include "SkSVGSVG.h"
#include "SkSVGValue.h"
SkSVGSVG::SkSVGSVG() : INHERITED(SkSVGTag::kSvg) { }
+bool SkSVGSVG::onPrepareToRender(SkSVGRenderContext* ctx) const {
+ auto viewPortRect = ctx->lengthContext().resolveRect(fX, fY, fWidth, fHeight);
+ auto contentMatrix = SkMatrix::MakeTrans(viewPortRect.x(), viewPortRect.y());
+ auto viewPort = SkSize::Make(viewPortRect.width(), viewPortRect.height());
+
+ if (fViewBox.isValid()) {
+ const SkRect& viewBox = *fViewBox.get();
+
+ // An empty viewbox disables rendering.
+ if (viewBox.isEmpty()) {
+ return false;
+ }
+
+ // A viewBox overrides the intrinsic viewport.
+ viewPort = SkSize::Make(viewBox.width(), viewBox.height());
+
+ contentMatrix.preConcat(
+ SkMatrix::MakeRectToRect(viewBox, viewPortRect, SkMatrix::kFill_ScaleToFit));
+ }
+
+ if (!contentMatrix.isIdentity()) {
+ ctx->canvas()->save();
+ ctx->canvas()->concat(contentMatrix);
+ }
+
+ if (viewPort != ctx->lengthContext().viewPort()) {
+ ctx->writableLengthContext()->setViewPort(viewPort);
+ }
+
+ return this->INHERITED::onPrepareToRender(ctx);
+}
+
void SkSVGSVG::setX(const SkSVGLength& x) {
fX = x;
}
@@ -26,6 +60,10 @@ void SkSVGSVG::setHeight(const SkSVGLength& h) {
fHeight = h;
}
+void SkSVGSVG::setViewBox(const SkSVGViewBoxType& vb) {
+ fViewBox.set(vb);
+}
+
void SkSVGSVG::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
switch (attr) {
case SkSVGAttribute::kX:
@@ -48,6 +86,11 @@ void SkSVGSVG::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
this->setHeight(*h);
}
break;
+ case SkSVGAttribute::kViewBox:
+ if (const auto* vb = v.as<SkSVGViewBoxValue>()) {
+ this->setViewBox(*vb);
+ }
+ break;
default:
this->INHERITED::onSetAttribute(attr, v);
}
diff --git a/experimental/svg/model/SkSVGSVG.h b/experimental/svg/model/SkSVGSVG.h
index 27631f5a31..ae4787cac3 100644
--- a/experimental/svg/model/SkSVGSVG.h
+++ b/experimental/svg/model/SkSVGSVG.h
@@ -10,6 +10,7 @@
#include "SkSVGContainer.h"
#include "SkSVGTypes.h"
+#include "SkTLazy.h"
class SkSVGSVG : public SkSVGContainer {
public:
@@ -21,8 +22,11 @@ public:
void setY(const SkSVGLength&);
void setWidth(const SkSVGLength&);
void setHeight(const SkSVGLength&);
+ void setViewBox(const SkSVGViewBoxType&);
protected:
+ bool onPrepareToRender(SkSVGRenderContext*) const override;
+
void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
private:
@@ -33,6 +37,8 @@ private:
SkSVGLength fWidth = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
SkSVGLength fHeight = SkSVGLength(100, SkSVGLength::Unit::kPercentage);
+ SkTLazy<SkSVGViewBoxType> fViewBox;
+
typedef SkSVGContainer INHERITED;
};
diff --git a/experimental/svg/model/SkSVGShape.cpp b/experimental/svg/model/SkSVGShape.cpp
index d26eff482d..ad4b5cedae 100644
--- a/experimental/svg/model/SkSVGShape.cpp
+++ b/experimental/svg/model/SkSVGShape.cpp
@@ -10,13 +10,13 @@
SkSVGShape::SkSVGShape(SkSVGTag t) : INHERITED(t) {}
-void SkSVGShape::onRender(SkCanvas* canvas, const SkSVGRenderContext& ctx) const {
- if (const SkPaint* fillPaint = ctx.fillPaint()) {
- this->onDraw(canvas, ctx.lengthContext(), *fillPaint);
+void SkSVGShape::onRender(const SkSVGRenderContext& ctx) const {
+ if (const SkPaint* fillPaint = ctx.presentationContext().fillPaint()) {
+ this->onDraw(ctx.canvas(), ctx.lengthContext(), *fillPaint);
}
- if (const SkPaint* strokePaint = ctx.strokePaint()) {
- this->onDraw(canvas, ctx.lengthContext(), *strokePaint);
+ if (const SkPaint* strokePaint = ctx.presentationContext().strokePaint()) {
+ this->onDraw(ctx.canvas(), ctx.lengthContext(), *strokePaint);
}
}
diff --git a/experimental/svg/model/SkSVGShape.h b/experimental/svg/model/SkSVGShape.h
index 2b3ea96d54..1f3c4555c3 100644
--- a/experimental/svg/model/SkSVGShape.h
+++ b/experimental/svg/model/SkSVGShape.h
@@ -22,7 +22,7 @@ public:
protected:
SkSVGShape(SkSVGTag);
- void onRender(SkCanvas*, const SkSVGRenderContext&) const final;
+ void onRender(const SkSVGRenderContext&) const final;
virtual void onDraw(SkCanvas*, const SkSVGLengthContext&, const SkPaint&) const = 0;
diff --git a/experimental/svg/model/SkSVGTransformableNode.cpp b/experimental/svg/model/SkSVGTransformableNode.cpp
index 3636754fcc..2686a4c542 100644
--- a/experimental/svg/model/SkSVGTransformableNode.cpp
+++ b/experimental/svg/model/SkSVGTransformableNode.cpp
@@ -5,6 +5,8 @@
* found in the LICENSE file.
*/
+#include "SkCanvas.h"
+#include "SkSVGRenderContext.h"
#include "SkSVGTransformableNode.h"
#include "SkSVGValue.h"
@@ -12,6 +14,16 @@ SkSVGTransformableNode::SkSVGTransformableNode(SkSVGTag tag)
: INHERITED(tag)
, fMatrix(SkMatrix::I()) { }
+
+bool SkSVGTransformableNode::onPrepareToRender(SkSVGRenderContext* ctx) const {
+ if (!fMatrix.isIdentity()) {
+ ctx->canvas()->save();
+ ctx->canvas()->concat(fMatrix);
+ }
+
+ return this->INHERITED::onPrepareToRender(ctx);
+}
+
void SkSVGTransformableNode::onSetAttribute(SkSVGAttribute attr, const SkSVGValue& v) {
switch (attr) {
case SkSVGAttribute::kTransform:
diff --git a/experimental/svg/model/SkSVGTransformableNode.h b/experimental/svg/model/SkSVGTransformableNode.h
index c345e8594f..475fafb44f 100644
--- a/experimental/svg/model/SkSVGTransformableNode.h
+++ b/experimental/svg/model/SkSVGTransformableNode.h
@@ -20,9 +20,9 @@ public:
protected:
SkSVGTransformableNode(SkSVGTag);
- void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
+ bool onPrepareToRender(SkSVGRenderContext*) const override;
- const SkMatrix& onLocalMatrix() const override { return fMatrix; }
+ void onSetAttribute(SkSVGAttribute, const SkSVGValue&) override;
private:
// FIXME: should be sparse
diff --git a/experimental/svg/model/SkSVGTypes.h b/experimental/svg/model/SkSVGTypes.h
index 6d34d9943a..ab07d7b16c 100644
--- a/experimental/svg/model/SkSVGTypes.h
+++ b/experimental/svg/model/SkSVGTypes.h
@@ -9,25 +9,30 @@
#define SkSVGTypes_DEFINED
#include "SkColor.h"
+#include "SkRect.h"
#include "SkScalar.h"
#include "SkTypes.h"
-class SkSVGNumber {
+template <typename T>
+class SkSVGPrimitiveTypeWrapper {
public:
- constexpr SkSVGNumber() : fValue(0) {}
- explicit constexpr SkSVGNumber(SkScalar v) : fValue(v) {}
- SkSVGNumber(const SkSVGNumber&) = default;
- SkSVGNumber& operator=(const SkSVGNumber&) = default;
+ SkSVGPrimitiveTypeWrapper() = default;
+ explicit constexpr SkSVGPrimitiveTypeWrapper(T v) : fValue(v) {}
+ SkSVGPrimitiveTypeWrapper(const SkSVGPrimitiveTypeWrapper&) = default;
+ SkSVGPrimitiveTypeWrapper& operator=(const SkSVGPrimitiveTypeWrapper&) = default;
- const SkScalar& value() const { return fValue; }
-
- operator const SkScalar&() const { return fValue; }
+ const T& value() const { return fValue; }
+ operator const T&() const { return fValue; }
private:
- SkScalar fValue;
+ T fValue;
};
+using SkSVGColorType = SkSVGPrimitiveTypeWrapper<SkColor >;
+using SkSVGNumberType = SkSVGPrimitiveTypeWrapper<SkScalar>;
+using SkSVGViewBoxType = SkSVGPrimitiveTypeWrapper<SkRect >;
+
class SkSVGLength {
public:
enum class Unit {
@@ -58,15 +63,4 @@ private:
Unit fUnit;
};
-class SkSVGColor {
-public:
- constexpr SkSVGColor() : fValue(SK_ColorBLACK) {}
- explicit constexpr SkSVGColor(SkColor c) : fValue(c) {}
-
- operator const SkColor&() const { return fValue; }
-
-private:
- SkColor fValue;
-};
-
#endif // SkSVGTypes_DEFINED
diff --git a/experimental/svg/model/SkSVGValue.h b/experimental/svg/model/SkSVGValue.h
index a83c4fe07f..77619c2241 100644
--- a/experimental/svg/model/SkSVGValue.h
+++ b/experimental/svg/model/SkSVGValue.h
@@ -21,6 +21,7 @@ public:
kLength,
kPath,
kTransform,
+ kViewBox,
};
Type type() const { return fType; }
@@ -39,26 +40,31 @@ private:
typedef SkNoncopyable INHERITED;
};
-template <typename SkiaType, SkSVGValue::Type ValueType>
+template <typename T, SkSVGValue::Type ValueType>
class SkSVGWrapperValue final : public SkSVGValue {
public:
static constexpr Type TYPE = ValueType;
- explicit SkSVGWrapperValue(const SkiaType& v)
+ explicit SkSVGWrapperValue(const T& v)
: INHERITED(ValueType)
, fWrappedValue(v) { }
- operator const SkiaType&() const { return fWrappedValue; }
+ operator const T&() const { return fWrappedValue; }
private:
- SkiaType fWrappedValue;
+ // Stack-only
+ void* operator new(size_t) = delete;
+ void* operator new(size_t, void*) = delete;
+
+ const T& fWrappedValue;
typedef SkSVGValue INHERITED;
};
-using SkSVGColorValue = SkSVGWrapperValue<SkSVGColor , SkSVGValue::Type::kColor >;
-using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength, SkSVGValue::Type::kLength >;
-using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >;
-using SkSVGTransformValue = SkSVGWrapperValue<SkMatrix , SkSVGValue::Type::kTransform>;
+using SkSVGColorValue = SkSVGWrapperValue<SkSVGColorType , SkSVGValue::Type::kColor >;
+using SkSVGLengthValue = SkSVGWrapperValue<SkSVGLength , SkSVGValue::Type::kLength >;
+using SkSVGPathValue = SkSVGWrapperValue<SkPath , SkSVGValue::Type::kPath >;
+using SkSVGTransformValue = SkSVGWrapperValue<SkMatrix , SkSVGValue::Type::kTransform>;
+using SkSVGViewBoxValue = SkSVGWrapperValue<SkSVGViewBoxType, SkSVGValue::Type::kViewBox >;
#endif // SkSVGValue_DEFINED