From 53281c712159aeb933d23c148a8ad6f67c9cea01 Mon Sep 17 00:00:00 2001 From: Tyler Denniston Date: Thu, 22 Oct 2020 15:54:24 -0400 Subject: [PATCH] [svg] Add current node to render context A couple of render-time decisions require knowledge of object bounding boxes, such as gradients (whose default coordinate space is "objectBoundingBox". This CL adds the current node being rendered to the render context so that it can be accessed down-stack (for example, when gradients are being resolved and added to the paint as Skia shaders). Each node will overload the bounds computation, for now it just returns empty bounds for all nodes. TBD if we want to cache bounds somewhere, either inside the node object or in a separate cache. Bug: skia:10842 Change-Id: I40061ffedcb840e4dd28dba6351421f5b4fc904b Reviewed-on: https://skia-review.googlesource.com/c/skia/+/329221 Commit-Queue: Tyler Denniston Reviewed-by: Florin Malita --- modules/svg/include/SkSVGNode.h | 6 ++++++ modules/svg/include/SkSVGRenderContext.h | 8 +++++++- modules/svg/src/SkSVGDOM.cpp | 2 +- modules/svg/src/SkSVGNode.cpp | 6 +++++- modules/svg/src/SkSVGRenderContext.cpp | 21 ++++++++++++++++----- 5 files changed, 35 insertions(+), 8 deletions(-) diff --git a/modules/svg/include/SkSVGNode.h b/modules/svg/include/SkSVGNode.h index a2991f14182db..001b5ca67901f 100644 --- a/modules/svg/include/SkSVGNode.h +++ b/modules/svg/include/SkSVGNode.h @@ -15,6 +15,7 @@ class SkCanvas; class SkMatrix; class SkPaint; class SkPath; +class SkSVGLengthContext; class SkSVGRenderContext; class SkSVGValue; @@ -72,6 +73,7 @@ class SkSVGNode : public SkRefCnt { void render(const SkSVGRenderContext&) const; bool asPaint(const SkSVGRenderContext&, SkPaint*) const; SkPath asPath(const SkSVGRenderContext&) const; + SkRect objectBoundingBox(const SkSVGLengthContext&) const; void setAttribute(SkSVGAttribute, const SkSVGValue&); bool setAttribute(const char* attributeName, const char* attributeValue); @@ -119,6 +121,10 @@ class SkSVGNode : public SkRefCnt { virtual bool hasChildren() const { return false; } + virtual SkRect onObjectBoundingBox(const SkSVGLengthContext&) const { + return SkRect::MakeEmpty(); + } + private: SkSVGTag fTag; diff --git a/modules/svg/include/SkSVGRenderContext.h b/modules/svg/include/SkSVGRenderContext.h index 0659a89e3df71..8b535f3e5c14a 100644 --- a/modules/svg/include/SkSVGRenderContext.h +++ b/modules/svg/include/SkSVGRenderContext.h @@ -59,9 +59,10 @@ struct SkSVGPresentationContext { class SkSVGRenderContext { public: SkSVGRenderContext(SkCanvas*, const SkSVGIDMapper&, const SkSVGLengthContext&, - const SkSVGPresentationContext&); + const SkSVGPresentationContext&, const SkSVGNode*); SkSVGRenderContext(const SkSVGRenderContext&); SkSVGRenderContext(const SkSVGRenderContext&, SkCanvas*); + SkSVGRenderContext(const SkSVGRenderContext&, const SkSVGNode*); ~SkSVGRenderContext(); const SkSVGLengthContext& lengthContext() const { return *fLengthContext; } @@ -119,6 +120,9 @@ class SkSVGRenderContext { // The local computed clip path (not inherited). const SkPath* clipPath() const { return fClipPath.getMaybeNull(); } + // The node being rendered (may be null). + const SkSVGNode* node() const { return fNode; } + private: // Stack-only void* operator new(size_t) = delete; @@ -139,6 +143,8 @@ class SkSVGRenderContext { // clipPath, if present for the current context (not inherited). SkTLazy fClipPath; + + const SkSVGNode* fNode; }; #endif // SkSVGRenderContext_DEFINED diff --git a/modules/svg/src/SkSVGDOM.cpp b/modules/svg/src/SkSVGDOM.cpp index 27e2540773c7b..b989b7000806d 100644 --- a/modules/svg/src/SkSVGDOM.cpp +++ b/modules/svg/src/SkSVGDOM.cpp @@ -593,7 +593,7 @@ void SkSVGDOM::render(SkCanvas* canvas) const { if (fRoot) { SkSVGLengthContext lctx(fContainerSize); SkSVGPresentationContext pctx; - fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx)); + fRoot->render(SkSVGRenderContext(canvas, fIDMapper, lctx, pctx, nullptr)); } } diff --git a/modules/svg/src/SkSVGNode.cpp b/modules/svg/src/SkSVGNode.cpp index ce05aa54d7ac3..cf12945d2db61 100644 --- a/modules/svg/src/SkSVGNode.cpp +++ b/modules/svg/src/SkSVGNode.cpp @@ -19,7 +19,7 @@ SkSVGNode::SkSVGNode(SkSVGTag t) : fTag(t) { } SkSVGNode::~SkSVGNode() { } void SkSVGNode::render(const SkSVGRenderContext& ctx) const { - SkSVGRenderContext localContext(ctx); + SkSVGRenderContext localContext(ctx, this); if (this->onPrepareToRender(&localContext)) { this->onRender(localContext); @@ -48,6 +48,10 @@ SkPath SkSVGNode::asPath(const SkSVGRenderContext& ctx) const { return path; } +SkRect SkSVGNode::objectBoundingBox(const SkSVGLengthContext& lctx) const { + return this->onObjectBoundingBox(lctx); +} + bool SkSVGNode::onPrepareToRender(SkSVGRenderContext* ctx) const { ctx->applyPresentationAttributes(fPresentationAttributes, this->hasChildren() ? 0 : SkSVGRenderContext::kLeaf); diff --git a/modules/svg/src/SkSVGRenderContext.cpp b/modules/svg/src/SkSVGRenderContext.cpp index 759c5cf902695..4b1b93b87adcb 100644 --- a/modules/svg/src/SkSVGRenderContext.cpp +++ b/modules/svg/src/SkSVGRenderContext.cpp @@ -317,7 +317,7 @@ SkSVGPresentationContext::SkSVGPresentationContext() // Commit initial values to the paint cache. SkCanvas fakeCanvas(0, 0); SkSVGRenderContext fake(&fakeCanvas, SkSVGIDMapper(), SkSVGLengthContext(SkSize::Make(0, 0)), - *this); + *this, nullptr); commitToPaint(fInherited, fake, this); commitToPaint(fInherited, fake, this); @@ -332,24 +332,35 @@ SkSVGPresentationContext::SkSVGPresentationContext() SkSVGRenderContext::SkSVGRenderContext(SkCanvas* canvas, const SkSVGIDMapper& mapper, const SkSVGLengthContext& lctx, - const SkSVGPresentationContext& pctx) + const SkSVGPresentationContext& pctx, + const SkSVGNode* node) : fIDMapper(mapper) , fLengthContext(lctx) , fPresentationContext(pctx) , fCanvas(canvas) - , fCanvasSaveCount(canvas->getSaveCount()) {} + , fCanvasSaveCount(canvas->getSaveCount()) + , fNode(node) {} SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other) : SkSVGRenderContext(other.fCanvas, other.fIDMapper, *other.fLengthContext, - *other.fPresentationContext) {} + *other.fPresentationContext, + other.fNode) {} SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, SkCanvas* canvas) : SkSVGRenderContext(canvas, other.fIDMapper, *other.fLengthContext, - *other.fPresentationContext) {} + *other.fPresentationContext, + other.fNode) {} + +SkSVGRenderContext::SkSVGRenderContext(const SkSVGRenderContext& other, const SkSVGNode* node) + : SkSVGRenderContext(other.fCanvas, + other.fIDMapper, + *other.fLengthContext, + *other.fPresentationContext, + node) {} SkSVGRenderContext::~SkSVGRenderContext() { fCanvas->restoreToCount(fCanvasSaveCount);