[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 <tdenniston@google.com>
Reviewed-by: Florin Malita <fmalita@chromium.org>
diff --git a/modules/svg/include/SkSVGNode.h b/modules/svg/include/SkSVGNode.h
index a2991f1..001b5ca 100644
--- a/modules/svg/include/SkSVGNode.h
+++ b/modules/svg/include/SkSVGNode.h
@@ -15,6 +15,7 @@
 class SkMatrix;
 class SkPaint;
 class SkPath;
+class SkSVGLengthContext;
 class SkSVGRenderContext;
 class SkSVGValue;
 
@@ -72,6 +73,7 @@
     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 @@
 
     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 0659a89..8b535f3 100644
--- a/modules/svg/include/SkSVGRenderContext.h
+++ b/modules/svg/include/SkSVGRenderContext.h
@@ -59,9 +59,10 @@
 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 @@
     // 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 @@
 
     // clipPath, if present for the current context (not inherited).
     SkTLazy<SkPath>                               fClipPath;
+
+    const SkSVGNode* fNode;
 };
 
 #endif // SkSVGRenderContext_DEFINED
diff --git a/modules/svg/src/SkSVGDOM.cpp b/modules/svg/src/SkSVGDOM.cpp
index 27e2540..b989b70 100644
--- a/modules/svg/src/SkSVGDOM.cpp
+++ b/modules/svg/src/SkSVGDOM.cpp
@@ -593,7 +593,7 @@
     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 ce05aa5..cf12945 100644
--- a/modules/svg/src/SkSVGNode.cpp
+++ b/modules/svg/src/SkSVGNode.cpp
@@ -19,7 +19,7 @@
 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 @@
     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 759c5cf..4b1b93b 100644
--- a/modules/svg/src/SkSVGRenderContext.cpp
+++ b/modules/svg/src/SkSVGRenderContext.cpp
@@ -317,7 +317,7 @@
     // Commit initial values to the paint cache.
     SkCanvas fakeCanvas(0, 0);
     SkSVGRenderContext fake(&fakeCanvas, SkSVGIDMapper(), SkSVGLengthContext(SkSize::Make(0, 0)),
-                             *this);
+                             *this, nullptr);
 
     commitToPaint<SkSVGAttribute::kFill>(fInherited, fake, this);
     commitToPaint<SkSVGAttribute::kFillOpacity>(fInherited, fake, this);
@@ -332,24 +332,35 @@
 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);