From 397a517d1a5774653fcdd08172f9a6b5eea67621 Mon Sep 17 00:00:00 2001 From: fmalita Date: Mon, 8 Aug 2016 11:38:55 -0700 Subject: [SVGDom] Add viewBox support The main feature is 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 --- experimental/svg/model/SkSVGAttribute.cpp | 10 ++-- experimental/svg/model/SkSVGAttribute.h | 15 +++--- experimental/svg/model/SkSVGAttributeParser.cpp | 27 +++++++++-- experimental/svg/model/SkSVGAttributeParser.h | 5 +- experimental/svg/model/SkSVGContainer.cpp | 4 +- experimental/svg/model/SkSVGContainer.h | 2 +- experimental/svg/model/SkSVGDOM.cpp | 21 +++++++-- experimental/svg/model/SkSVGNode.cpp | 23 ++++----- experimental/svg/model/SkSVGNode.h | 14 ++++-- experimental/svg/model/SkSVGRect.cpp | 8 +--- experimental/svg/model/SkSVGRenderContext.cpp | 51 ++++++++++++++++---- experimental/svg/model/SkSVGRenderContext.h | 57 ++++++++++++++++++----- experimental/svg/model/SkSVGSVG.cpp | 43 +++++++++++++++++ experimental/svg/model/SkSVGSVG.h | 6 +++ experimental/svg/model/SkSVGShape.cpp | 10 ++-- experimental/svg/model/SkSVGShape.h | 2 +- experimental/svg/model/SkSVGTransformableNode.cpp | 12 +++++ experimental/svg/model/SkSVGTransformableNode.h | 4 +- experimental/svg/model/SkSVGTypes.h | 34 ++++++-------- experimental/svg/model/SkSVGValue.h | 22 +++++---- 20 files changed, 265 insertions(+), 105 deletions(-) (limited to 'experimental/svg') 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& 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&) 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 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, 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& 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& node, SkSVGAttribute attr, return true; } +bool SetViewBoxAttribute(const sk_sp& 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 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::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 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) = 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 fFill; - SkTLazy fStroke; + // TODO: convert to regular SkPaints and track explicit attribute values instead. + SkTLazy fFill; + SkTLazy 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 fLengthContext; + SkTCopyOnFirstWrite 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()) { + 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 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 +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; +using SkSVGNumberType = SkSVGPrimitiveTypeWrapper; +using SkSVGViewBoxType = SkSVGPrimitiveTypeWrapper; + 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 +template 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; -using SkSVGLengthValue = SkSVGWrapperValue; -using SkSVGPathValue = SkSVGWrapperValue; -using SkSVGTransformValue = SkSVGWrapperValue; +using SkSVGColorValue = SkSVGWrapperValue; +using SkSVGLengthValue = SkSVGWrapperValue; +using SkSVGPathValue = SkSVGWrapperValue; +using SkSVGTransformValue = SkSVGWrapperValue; +using SkSVGViewBoxValue = SkSVGWrapperValue; #endif // SkSVGValue_DEFINED -- cgit v1.2.3