allow pictures to have a full bounds

BUG=skia:

Review URL: https://codereview.chromium.org/736583004
diff --git a/include/core/SkBBHFactory.h b/include/core/SkBBHFactory.h
index 67c9cd7..2cc37e5 100644
--- a/include/core/SkBBHFactory.h
+++ b/include/core/SkBBHFactory.h
@@ -9,7 +9,7 @@
 #define SkBBHFactory_DEFINED
 
 #include "SkSize.h"
-#include "SkPoint.h"
+#include "SkRect.h"
 
 class SkBBoxHierarchy;
 
@@ -18,13 +18,13 @@
     /**
      *  Allocate a new SkBBoxHierarchy. Return NULL on failure.
      */
-    virtual SkBBoxHierarchy* operator()(int width, int height) const = 0;
+    virtual SkBBoxHierarchy* operator()(const SkRect& bounds) const = 0;
     virtual ~SkBBHFactory() {};
 };
 
 class SK_API SkRTreeFactory : public SkBBHFactory {
 public:
-    virtual SkBBoxHierarchy* operator()(int width, int height) const SK_OVERRIDE;
+    virtual SkBBoxHierarchy* operator()(const SkRect& bounds) const SK_OVERRIDE;
 private:
     typedef SkBBHFactory INHERITED;
 };
@@ -50,7 +50,7 @@
 
     SkTileGridFactory(const TileGridInfo& info) : fInfo(info) { }
 
-    virtual SkBBoxHierarchy* operator()(int width, int height) const SK_OVERRIDE;
+    virtual SkBBoxHierarchy* operator()(const SkRect& bounds) const SK_OVERRIDE;
 
 private:
     TileGridInfo fInfo;
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 276b392..d172674 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -1335,7 +1335,7 @@
         kDefault_InitFlags                  = 0,
         kConservativeRasterClip_InitFlag    = 1 << 0,
     };
-    SkCanvas(int width, int height, InitFlags);
+    SkCanvas(const SkIRect& bounds, InitFlags);
     SkCanvas(SkBaseDevice*, const SkSurfaceProps*, InitFlags);
     SkCanvas(const SkBitmap&, const SkSurfaceProps&);
 
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index 471a76b..3c26bac 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -53,6 +53,12 @@
         bounds->setXYWH(origin.x(), origin.y(), this->width(), this->height());
     }
 
+    SkIRect getGlobalBounds() const {
+        SkIRect bounds;
+        this->getGlobalBounds(&bounds);
+        return bounds;
+    }
+
     int width() const {
         return this->imageInfo().width();
     }
@@ -366,6 +372,7 @@
     friend class SkDeviceFilteredPaint;
     friend class SkDeviceImageFilterProxy;
     friend class SkDeferredDevice;    // for newSurface
+    friend class SkNoPixelsBitmapDevice;
 
     friend class SkSurface_Raster;
 
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 99bca36..c69db37 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -130,7 +130,7 @@
         It does not necessarily reflect the bounds of what has been recorded into the picture.
         @return the cull rect used to create this picture
     */
-    const SkRect cullRect() const { return SkRect::MakeWH(fCullWidth, fCullHeight); }
+    SkRect cullRect() const { return fCullRect; }
 
     /** Return a non-zero, unique value representing the picture. This call is
         only valid when not recording. Between a beginRecording/endRecording
@@ -260,15 +260,14 @@
     static bool IsValidPictInfo(const SkPictInfo& info);
 
     // Takes ownership of the SkRecord, refs the (optional) drawablePicts and BBH.
-    SkPicture(SkScalar width, SkScalar height, SkRecord*, SkData* drawablePicts,
+    SkPicture(const SkRect& cullRect, SkRecord*, SkData* drawablePicts,
               SkBBoxHierarchy*);
 
     static SkPicture* Forwardport(const SkPictInfo&, const SkPictureData*);
     static SkPictureData* Backport(const SkRecord&, const SkPictInfo&,
                                    SkPicture const* const drawablePics[], int drawableCount);
 
-    const SkScalar                        fCullWidth;
-    const SkScalar                        fCullHeight;
+    const SkRect                          fCullRect;
     mutable SkAutoTUnref<const AccelData> fAccelData;
     mutable SkTDArray<DeletionListener*> fDeletionListeners;  // pointers are refed
     SkAutoTDelete<SkRecord>       fRecord;
diff --git a/include/core/SkPictureRecorder.h b/include/core/SkPictureRecorder.h
index de216b4..a8ca600 100644
--- a/include/core/SkPictureRecorder.h
+++ b/include/core/SkPictureRecorder.h
@@ -50,10 +50,16 @@
         @param recordFlags optional flags that control recording.
         @return the canvas.
     */
-    SkCanvas* beginRecording(SkScalar width, SkScalar height,
+    SkCanvas* beginRecording(const SkRect& bounds,
                              SkBBHFactory* bbhFactory = NULL,
                              uint32_t recordFlags = 0);
 
+    SkCanvas* beginRecording(SkScalar width, SkScalar height,
+                             SkBBHFactory* bbhFactory = NULL,
+                             uint32_t recordFlags = 0) {
+        return this->beginRecording(SkRect::MakeWH(width, height), bbhFactory, recordFlags);
+    }
+
     /** Returns the recording canvas if one is active, or NULL if recording is
         not active. This does not alter the refcnt on the canvas (if present).
     */
@@ -79,8 +85,7 @@
     void partialReplay(SkCanvas* canvas) const;
 
     uint32_t                      fFlags;
-    SkScalar                      fCullWidth;
-    SkScalar                      fCullHeight;
+    SkRect                        fCullRect;
     SkAutoTUnref<SkBBoxHierarchy> fBBH;
     SkAutoTUnref<SkRecorder>      fRecorder;
     SkAutoTDelete<SkRecord>       fRecord;
diff --git a/samplecode/SampleArc.cpp b/samplecode/SampleArc.cpp
index a44eeb5..ecea90b 100644
--- a/samplecode/SampleArc.cpp
+++ b/samplecode/SampleArc.cpp
@@ -37,6 +37,27 @@
     SkParsePath::ToSVGString(p2, &str2);
 }
 
+#include "SkPictureRecorder.h"
+static void test_pictbounds(SkCanvas* canvas) {
+    SkRect r = SkRect::MakeXYWH(100, 50, 100, 100);
+    SkPictureRecorder recorder;
+    {
+        SkCanvas* c = recorder.beginRecording(r, NULL, 0);
+        c->drawOval(r, SkPaint());
+
+        SkIRect ir;
+        c->getClipDeviceBounds(&ir);
+        SkDebugf("devbounds [%d %d %d %d]\n", ir.left(), ir.top(), ir.right(), ir.bottom());
+
+        SkASSERT(!c->quickReject(r));
+    }
+    SkPicture* pic = recorder.endRecording();
+
+    canvas->drawPicture(pic);
+    SkASSERT(pic->cullRect() == r);
+    pic->unref();
+}
+
 class ArcsView : public SampleView {
     class MyDrawable : public SkCanvasDrawable {
         SkRect   fR;
@@ -176,6 +197,8 @@
     }
 
     virtual void onDrawContent(SkCanvas* canvas) {
+        if (true) { test_pictbounds(canvas); return; }
+
         fDrawable->setSweep(SampleCode::GetAnimScalar(SkIntToScalar(360)/24,
                                                       SkIntToScalar(360)));
 
diff --git a/src/core/SkBBHFactory.cpp b/src/core/SkBBHFactory.cpp
index 22f816c..4b9ae55 100644
--- a/src/core/SkBBHFactory.cpp
+++ b/src/core/SkBBHFactory.cpp
@@ -9,15 +9,20 @@
 #include "SkRTree.h"
 #include "SkTileGrid.h"
 
-
-SkBBoxHierarchy* SkRTreeFactory::operator()(int width, int height) const {
-    SkScalar aspectRatio = SkScalarDiv(SkIntToScalar(width), SkIntToScalar(height));
+SkBBoxHierarchy* SkRTreeFactory::operator()(const SkRect& bounds) const {
+    SkScalar aspectRatio = bounds.width() / bounds.height();
     return SkNEW_ARGS(SkRTree, (aspectRatio));
 }
 
-SkBBoxHierarchy* SkTileGridFactory::operator()(int width, int height) const {
+SkBBoxHierarchy* SkTileGridFactory::operator()(const SkRect& bounds) const {
     SkASSERT(fInfo.fMargin.width() >= 0);
     SkASSERT(fInfo.fMargin.height() >= 0);
+
+    // We want a conservative answer for the size...
+    const SkIRect ibounds = bounds.roundOut();
+    const int width = ibounds.width();
+    const int height = ibounds.height();
+
     // Note: SkIRects are non-inclusive of the right() column and bottom() row.
     // For example, an SkIRect at 0,0 with a size of (1,1) will only have
     // content at pixel (0,0) and will report left=0 and right=1, hence the
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 4fda7a3..31a9a79 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -431,7 +431,7 @@
         }
         device->onAttachToCanvas(this);
         fMCRec->fLayer->fDevice = SkRef(device);
-        fMCRec->fRasterClip.setRect(SkIRect::MakeWH(device->width(), device->height()));
+        fMCRec->fRasterClip.setRect(device->getGlobalBounds());
     }
     return device;
 }
@@ -453,7 +453,11 @@
 
 class SkNoPixelsBitmapDevice : public SkBitmapDevice {
 public:
-    SkNoPixelsBitmapDevice(int width, int height) : INHERITED(make_nopixels(width, height)) {}
+    SkNoPixelsBitmapDevice(const SkIRect& bounds)
+        : INHERITED(make_nopixels(bounds.width(), bounds.height()))
+    {
+        this->setOrigin(bounds.x(), bounds.y());
+    }
 
 private:
 
@@ -466,16 +470,17 @@
 {
     inc_canvas();
 
-    this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), kDefault_InitFlags)->unref();
+    this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice,
+                          (SkIRect::MakeWH(width, height))), kDefault_InitFlags)->unref();
 }
 
-SkCanvas::SkCanvas(int width, int height, InitFlags flags)
+SkCanvas::SkCanvas(const SkIRect& bounds, InitFlags flags)
     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
     , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
 {
     inc_canvas();
 
-    this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (width, height)), flags)->unref();
+    this->init(SkNEW_ARGS(SkNoPixelsBitmapDevice, (bounds)), flags)->unref();
 }
 
 SkCanvas::SkCanvas(SkBaseDevice* device, const SkSurfaceProps* props, InitFlags flags)
diff --git a/src/core/SkCanvasDrawable.cpp b/src/core/SkCanvasDrawable.cpp
index 0065d43..e0120f0 100644
--- a/src/core/SkCanvasDrawable.cpp
+++ b/src/core/SkCanvasDrawable.cpp
@@ -23,9 +23,22 @@
 
 SkCanvasDrawable::SkCanvasDrawable() : fGenerationID(0) {}
 
+static void draw_bbox(SkCanvas* canvas, const SkRect& r) {
+    SkPaint paint;
+    paint.setStyle(SkPaint::kStroke_Style);
+    paint.setColor(0xFFFF7088);
+    canvas->drawRect(r, paint);
+    canvas->drawLine(r.left(), r.top(), r.right(), r.bottom(), paint);
+    canvas->drawLine(r.left(), r.bottom(), r.right(), r.top(), paint);
+}
+
 void SkCanvasDrawable::draw(SkCanvas* canvas) {
     SkAutoCanvasRestore acr(canvas, true);
     this->onDraw(canvas);
+
+    if (false) {
+        draw_bbox(canvas, this->getBounds());
+    }
 }
 
 SkPicture* SkCanvasDrawable::newPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) {
@@ -52,8 +65,13 @@
 #include "SkPictureRecorder.h"
 
 SkPicture* SkCanvasDrawable::onNewPictureSnapshot(SkBBHFactory* bbhFactory, uint32_t recordFlags) {
-    const SkRect bounds = this->getBounds();
     SkPictureRecorder recorder;
-    this->draw(recorder.beginRecording(bounds.width(), bounds.height(), bbhFactory, recordFlags));
+
+    const SkRect bounds = this->getBounds();
+    SkCanvas* canvas = recorder.beginRecording(bounds, bbhFactory, recordFlags);
+    this->draw(canvas);
+    if (false) {
+        draw_bbox(canvas, bounds);
+    }
     return recorder.endRecording();
 }
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index 4c97cb7..7f4b33a 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -530,10 +530,9 @@
     return fUniqueID;
 }
 
-SkPicture::SkPicture(SkScalar width, SkScalar height, SkRecord* record, SkData* drawablePicts,
+SkPicture::SkPicture(const SkRect& cullRect, SkRecord* record, SkData* drawablePicts,
                      SkBBoxHierarchy* bbh)
-    : fCullWidth(width)
-    , fCullHeight(height)
+    : fCullRect(cullRect)
     , fRecord(record)
     , fBBH(SkSafeRef(bbh))
     , fDrawablePicts(SkSafeRef(drawablePicts))
diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp
index bc8bffb..aea9e38 100644
--- a/src/core/SkPictureRecorder.cpp
+++ b/src/core/SkPictureRecorder.cpp
@@ -18,20 +18,19 @@
 
 SkPictureRecorder::~SkPictureRecorder() {}
 
-SkCanvas* SkPictureRecorder::beginRecording(SkScalar width, SkScalar height,
+SkCanvas* SkPictureRecorder::beginRecording(const SkRect& cullRect,
                                             SkBBHFactory* bbhFactory /* = NULL */,
                                             uint32_t recordFlags /* = 0 */) {
+    fCullRect = cullRect;
     fFlags = recordFlags;
-    fCullWidth = width;
-    fCullHeight = height;
 
     if (bbhFactory) {
-        fBBH.reset((*bbhFactory)(width, height));
+        fBBH.reset((*bbhFactory)(cullRect));
         SkASSERT(fBBH.get());
     }
 
     fRecord.reset(SkNEW(SkRecord));
-    fRecorder.reset(SkNEW_ARGS(SkRecorder, (fRecord.get(), width, height)));
+    fRecorder.reset(SkNEW_ARGS(SkRecorder, (fRecord.get(), cullRect)));
     return this->getRecordingCanvas();
 }
 
@@ -52,12 +51,10 @@
     }
 
     if (fBBH.get()) {
-        SkRect cullRect = SkRect::MakeWH(fCullWidth, fCullHeight);
-
         if (saveLayerData) {
-            SkRecordComputeLayers(cullRect, *fRecord, fBBH.get(), saveLayerData);
+            SkRecordComputeLayers(fCullRect, *fRecord, fBBH.get(), saveLayerData);
         } else {
-            SkRecordFillBounds(cullRect, *fRecord, fBBH.get());
+            SkRecordFillBounds(fCullRect, *fRecord, fBBH.get());
         }
     }
 
@@ -65,7 +62,7 @@
     SkBBHFactory* factory = NULL;
     uint32_t recordFlags = 0;
     SkAutoDataUnref drawablePicts(fRecorder->newDrawableSnapshot(factory, recordFlags));
-    SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullWidth, fCullHeight, fRecord.detach(),
+    SkPicture* pict = SkNEW_ARGS(SkPicture, (fCullRect, fRecord.detach(),
                                              drawablePicts, fBBH.get()));
 
     if (saveLayerData) {
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 1af328a..998fb66 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -10,9 +10,13 @@
 #include "SkPatchUtils.h"
 #include "SkPicture.h"
 
-// SkCanvas will fail in mysterious ways if it doesn't know the real width and height.
 SkRecorder::SkRecorder(SkRecord* record, int width, int height)
-    : SkCanvas(width, height, SkCanvas::kConservativeRasterClip_InitFlag)
+    : SkCanvas(SkIRect::MakeWH(width, height), SkCanvas::kConservativeRasterClip_InitFlag)
+    , fRecord(record)
+    , fSaveLayerCount(0) {}
+
+SkRecorder::SkRecorder(SkRecord* record, const SkRect& bounds)
+    : SkCanvas(bounds.roundOut(), SkCanvas::kConservativeRasterClip_InitFlag)
     , fRecord(record)
     , fSaveLayerCount(0) {}
 
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 563f16d..7b2cbfe 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -18,7 +18,8 @@
 class SkRecorder : public SkCanvas {
 public:
     // Does not take ownership of the SkRecord.
-    SkRecorder(SkRecord*, int width, int height);
+    SkRecorder(SkRecord*, int width, int height);   // legacy version
+    SkRecorder(SkRecord*, const SkRect& bounds);
     virtual ~SkRecorder() SK_OVERRIDE;
 
     // return a (new or ref'd) data containing the array of pictures that were
diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp
index 5bc6037..c929833 100644
--- a/tests/PictureTest.cpp
+++ b/tests/PictureTest.cpp
@@ -1842,7 +1842,7 @@
 class SpoonFedBBHFactory : public SkBBHFactory {
 public:
     explicit SpoonFedBBHFactory(SkBBoxHierarchy* bbh) : fBBH(bbh) {}
-    virtual SkBBoxHierarchy* operator()(int width, int height) const {
+    SkBBoxHierarchy* operator()(const SkRect&) const SK_OVERRIDE {
         return SkRef(fBBH);
     }
 private: