Update SkPicture cull rects with RTree information

When computed, the RTree for an SkPicture will have a root
bounds that reflects the best bounding information available,
rather than the best estimate at the time the picture recorder
is created. Given that creators frequently don't know ahead of
time what will be drawn, the RTree bound is often tighter.

Perf testing on Chrome indicates a small raster performance
advantage. For upcoming painting changes in Chrome the
performance advantage is much larger.

BUG=

Committed: https://skia.googlesource.com/skia/+/2dd3b6647dc726f36fd8774b3d0d2e83b493aeac

Review URL: https://codereview.chromium.org/971803002
diff --git a/src/core/SkBBoxHierarchy.h b/src/core/SkBBoxHierarchy.h
index f925a91..1ea9e6bd 100644
--- a/src/core/SkBBoxHierarchy.h
+++ b/src/core/SkBBoxHierarchy.h
@@ -34,6 +34,9 @@
 
     virtual size_t bytesUsed() const = 0;
 
+    // Get the root bound.
+    virtual SkRect getRootBound() const = 0;
+
     SK_DECLARE_INST_COUNT(SkBBoxHierarchy)
 private:
     typedef SkRefCnt INHERITED;
diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp
index 42f8732..1972ad3 100644
--- a/src/core/SkPictureRecorder.cpp
+++ b/src/core/SkPictureRecorder.cpp
@@ -60,6 +60,10 @@
         } else {
             SkRecordFillBounds(fCullRect, *fRecord, fBBH.get());
         }
+        SkRect bbhBound = fBBH->getRootBound();
+        SkASSERT((bbhBound.isEmpty() || fCullRect.contains(bbhBound))
+            || (bbhBound.isEmpty() && fCullRect.isEmpty()));
+        fCullRect = bbhBound;
     }
 
     SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord, pictList, fBBH));
diff --git a/src/core/SkRTree.cpp b/src/core/SkRTree.cpp
index ba5843e..2fded6f 100644
--- a/src/core/SkRTree.cpp
+++ b/src/core/SkRTree.cpp
@@ -9,6 +9,14 @@
 
 SkRTree::SkRTree(SkScalar aspectRatio) : fCount(0), fAspectRatio(aspectRatio) {}
 
+SkRect SkRTree::getRootBound() const {
+    if (fCount) {
+        return fRoot.fBounds;
+    } else {
+        return SkRect::MakeEmpty();
+    }
+}
+
 void SkRTree::insert(const SkRect boundsArray[], int N) {
     SkASSERT(0 == fCount);
 
diff --git a/src/core/SkRTree.h b/src/core/SkRTree.h
index 320b0bd..9a118d4 100644
--- a/src/core/SkRTree.h
+++ b/src/core/SkRTree.h
@@ -52,6 +52,9 @@
     // Insertion count (not overall node count, which may be greater).
     int getCount() const { return fCount; }
 
+    // Get the root bound.
+    SkRect getRootBound() const SK_OVERRIDE;
+
     // These values were empirically determined to produce reasonable performance in most cases.
     static const int kMinChildren = 6,
                      kMaxChildren = 11;
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 9b08426..ba15c1b 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -248,7 +248,11 @@
         Bounds clip = SkRect::Make(devBounds);
         // We don't call adjustAndMap() because as its last step it would intersect the adjusted
         // clip bounds with the previous clip, exactly what we can't do when the clip grows.
-        fCurrentClipBounds = this->adjustForSaveLayerPaints(&clip) ? clip : fCullRect;
+        if (this->adjustForSaveLayerPaints(&clip)) {
+            fCurrentClipBounds = clip.intersect(fCullRect) ? clip : Bounds::MakeEmpty();
+        } else {
+            fCurrentClipBounds = fCullRect;
+        }
     }
 
     // Restore holds the devBounds for the clip after the {save,saveLayer}/restore block completes.
@@ -259,8 +263,11 @@
         // so they are not affected by the saveLayer's paint.
         const int kSavesToIgnore = 1;
         Bounds clip = SkRect::Make(op.devBounds);
-        fCurrentClipBounds =
-            this->adjustForSaveLayerPaints(&clip, kSavesToIgnore) ? clip : fCullRect;
+        if (this->adjustForSaveLayerPaints(&clip, kSavesToIgnore)) {
+            fCurrentClipBounds = clip.intersect(fCullRect) ? clip : Bounds::MakeEmpty();
+        } else {
+            fCurrentClipBounds = fCullRect;
+        }
     }
 
     // We also take advantage of SaveLayer bounds when present to further cut the clip down.
@@ -387,8 +394,12 @@
     Bounds bounds(const DrawPaint&) const { return fCurrentClipBounds; }
     Bounds bounds(const NoOp&)  const { return Bounds::MakeEmpty(); }    // NoOps don't draw.
 
-    Bounds bounds(const DrawSprite& op) const {  // Ignores the matrix.
-        return Bounds::MakeXYWH(op.left, op.top, op.bitmap.width(), op.bitmap.height());
+    Bounds bounds(const DrawSprite& op) const {  // Ignores the matrix, but respects the clip.
+        SkRect rect = Bounds::MakeXYWH(op.left, op.top, op.bitmap.width(), op.bitmap.height());
+        if (!rect.intersect(fCurrentClipBounds)) {
+            return Bounds::MakeEmpty();
+        }
+        return rect;
     }
 
     Bounds bounds(const DrawRect& op) const { return this->adjustAndMap(op.rect, &op.paint); }
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index 33e058c..ac750e9 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -1248,8 +1248,9 @@
 
 struct CountingBBH : public SkBBoxHierarchy {
     mutable int searchCalls;
+    SkRect rootBound;
 
-    CountingBBH() : searchCalls(0) {}
+    CountingBBH(const SkRect& bound) : searchCalls(0), rootBound(bound) {}
 
     void search(const SkRect& query, SkTDArray<unsigned>* results) const SK_OVERRIDE {
         this->searchCalls++;
@@ -1257,6 +1258,7 @@
 
     void insert(const SkRect[], int) SK_OVERRIDE {}
     virtual size_t bytesUsed() const SK_OVERRIDE { return 0; }
+    SkRect getRootBound() const SK_OVERRIDE { return rootBound; }
 };
 
 class SpoonFedBBHFactory : public SkBBHFactory {
@@ -1271,11 +1273,12 @@
 
 // When the canvas clip covers the full picture, we don't need to call the BBH.
 DEF_TEST(Picture_SkipBBH, r) {
-    CountingBBH bbh;
+    SkRect bound = SkRect::MakeWH(320, 240);
+    CountingBBH bbh(bound);
     SpoonFedBBHFactory factory(&bbh);
 
     SkPictureRecorder recorder;
-    recorder.beginRecording(320, 240, &factory);
+    recorder.beginRecording(bound, &factory);
     SkAutoTUnref<const SkPicture> picture(recorder.endRecording());
 
     SkCanvas big(640, 480), small(300, 200);
diff --git a/tests/RecordDrawTest.cpp b/tests/RecordDrawTest.cpp
index cf138b8..baee712 100644
--- a/tests/RecordDrawTest.cpp
+++ b/tests/RecordDrawTest.cpp
@@ -133,6 +133,7 @@
 
     void search(const SkRect& query, SkTDArray<unsigned>* results) const SK_OVERRIDE {}
     size_t bytesUsed() const SK_OVERRIDE { return 0; }
+    SkRect getRootBound() const SK_OVERRIDE { return SkRect::MakeEmpty(); }
 
     struct Entry {
         unsigned opIndex;