Try out scalar picture sizes

This paves the way for removing the 'fTile' parameter from SkPictureShader (although that should be a different CL). If we like this we could also move to providing an entire cull SkRect.

R=reed@google.com, mtklein@google.com, fmalita@google.com, fmalita@chromium.org

Author: robertphillips@google.com

Review URL: https://codereview.chromium.org/513983002
diff --git a/src/core/SkBBoxRecord.cpp b/src/core/SkBBoxRecord.cpp
index 5837a88..5fe42f9 100644
--- a/src/core/SkBBoxRecord.cpp
+++ b/src/core/SkBBoxRecord.cpp
@@ -313,8 +313,7 @@
 
 void SkBBoxRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
                                  const SkPaint* paint) {
-    SkRect bounds = SkRect::MakeWH(SkIntToScalar(picture->width()),
-                                   SkIntToScalar(picture->height()));
+    SkRect bounds = picture->cullRect();
     // todo: wonder if we should allow passing an optional matrix to transformBounds so we don't
     // end up transforming the rect twice.
     if (matrix) {
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 16459b0..2b08a94 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -2445,7 +2445,7 @@
         }
     }
 
-    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height());
+    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->cullRect());
 
     picture->draw(this);
 }
@@ -2549,16 +2549,16 @@
 ///////////////////////////////////////////////////////////////////////////////
 
 SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
-                                                 const SkPaint* paint, int width, int height)
+                                                 const SkPaint* paint, const SkRect& bounds)
     : fCanvas(canvas)
     , fSaveCount(canvas->getSaveCount())
 {
     if (NULL != paint) {
-        SkRect bounds = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
+        SkRect newBounds = bounds;
         if (matrix) {
-            matrix->mapRect(&bounds);
+            matrix->mapRect(&newBounds);
         }
-        canvas->saveLayer(&bounds, paint);
+        canvas->saveLayer(&newBounds, paint);
     } else if (NULL != matrix) {
         canvas->save();
     }
diff --git a/src/core/SkCanvasPriv.h b/src/core/SkCanvasPriv.h
index 9f66baa..dfae154 100644
--- a/src/core/SkCanvasPriv.h
+++ b/src/core/SkCanvasPriv.h
@@ -12,7 +12,7 @@
 
 class SkAutoCanvasMatrixPaint : SkNoncopyable {
 public:
-    SkAutoCanvasMatrixPaint(SkCanvas*, const SkMatrix*, const SkPaint*, int width, int height);
+    SkAutoCanvasMatrixPaint(SkCanvas*, const SkMatrix*, const SkPaint*, const SkRect& bounds);
     ~SkAutoCanvasMatrixPaint();
 
 private:
diff --git a/src/core/SkPicture.cpp b/src/core/SkPicture.cpp
index e958f96..92551d3 100644
--- a/src/core/SkPicture.cpp
+++ b/src/core/SkPicture.cpp
@@ -262,11 +262,11 @@
 #endif
 
 // fRecord OK
-SkPicture::SkPicture(int width, int height,
+SkPicture::SkPicture(SkScalar width, SkScalar height,
                      const SkPictureRecord& record,
                      bool deepCopyOps)
-    : fWidth(width)
-    , fHeight(height)
+    : fCullWidth(width)
+    , fCullHeight(height)
     , fAnalysis() {
     this->needsNewGenID();
 
@@ -277,10 +277,11 @@
 
 // Create an SkPictureData-backed SkPicture from an SkRecord.
 // This for compatibility with serialization code only.  This is not cheap.
-static SkPicture* backport(const SkRecord& src, int width, int height) {
+static SkPicture* backport(const SkRecord& src, const SkRect& cullRect) {
     SkPictureRecorder recorder;
     SkRecordDraw(src,
-                 recorder.DEPRECATED_beginRecording(width, height), NULL/*bbh*/, NULL/*callback*/);
+                 recorder.DEPRECATED_beginRecording(cullRect.width(), cullRect.height()), 
+                 NULL/*bbh*/, NULL/*callback*/);
     return recorder.endRecording();
 }
 
@@ -351,7 +352,7 @@
     // If the query contains the whole picture, don't bother with the BBH.
     SkRect clipBounds = { 0, 0, 0, 0 };
     (void)canvas->getClipBounds(&clipBounds);
-    const bool useBBH = !clipBounds.contains(SkRect::MakeWH(this->width(), this->height()));
+    const bool useBBH = !clipBounds.contains(this->cullRect());
 
     if (NULL != fData.get()) {
         SkPicturePlayback playback(this);
@@ -392,7 +393,32 @@
     // Check magic bytes.
     SkPictInfo info;
     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
-    if (!stream->read(&info, sizeof(info)) || !IsValidPictInfo(info)) {
+
+    if (!stream->read(&info.fMagic, sizeof(kMagic))) {
+        return false;
+    }
+
+    info.fVersion = stream->readU32();
+
+#ifndef V35_COMPATIBILITY_CODE
+    if (info.fVersion < 35) {
+        info.fCullRect.fLeft = 0;
+        info.fCullRect.fTop = 0;
+        info.fCullRect.fRight = SkIntToScalar(stream->readU32());
+        info.fCullRect.fBottom = SkIntToScalar(stream->readU32());
+    } else {
+#endif
+        info.fCullRect.fLeft = stream->readScalar();
+        info.fCullRect.fTop = stream->readScalar();
+        info.fCullRect.fRight = stream->readScalar();
+        info.fCullRect.fBottom = stream->readScalar();
+#ifndef V35_COMPATIBILITY_CODE
+    }
+#endif
+
+    info.fFlags = stream->readU32();
+
+    if (!IsValidPictInfo(info)) {
         return false;
     }
 
@@ -403,11 +429,33 @@
 }
 
 // fRecord OK
-bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer& buffer, SkPictInfo* pInfo) {
+bool SkPicture::InternalOnly_BufferIsSKP(SkReadBuffer* buffer, SkPictInfo* pInfo) {
     // Check magic bytes.
     SkPictInfo info;
     SkASSERT(sizeof(kMagic) == sizeof(info.fMagic));
-    if (!buffer.readByteArray(&info, sizeof(info)) || !IsValidPictInfo(info)) {
+
+    if (!buffer->readByteArray(&info.fMagic, sizeof(kMagic))) {
+        return false;
+    }
+
+    info.fVersion = buffer->readUInt();
+
+#ifndef V35_COMPATIBILITY_CODE
+    if (info.fVersion < 35) {
+        info.fCullRect.fLeft = 0;
+        info.fCullRect.fTop = 0;
+        info.fCullRect.fRight = SkIntToScalar(buffer->readUInt());
+        info.fCullRect.fBottom = SkIntToScalar(buffer->readUInt());
+    } else {
+#endif
+        buffer->readRect(&info.fCullRect);
+#ifndef V35_COMPATIBILITY_CODE
+    }
+#endif
+
+    info.fFlags = buffer->readUInt();
+
+    if (!IsValidPictInfo(info)) {
         return false;
     }
 
@@ -418,19 +466,20 @@
 }
 
 // fRecord OK
-SkPicture::SkPicture(SkPictureData* data, int width, int height)
+SkPicture::SkPicture(SkPictureData* data, SkScalar width, SkScalar height)
     : fData(data)
-    , fWidth(width)
-    , fHeight(height)
+    , fCullWidth(width)
+    , fCullHeight(height)
     , fAnalysis() {
     this->needsNewGenID();
 }
 
 SkPicture* SkPicture::Forwardport(const SkPicture& src) {
     SkAutoTDelete<SkRecord> record(SkNEW(SkRecord));
-    SkRecorder canvas(record.get(), src.width(), src.height());
+    SkRecorder canvas(record.get(), src.cullRect().width(), src.cullRect().height());
     src.draw(&canvas);
-    return SkNEW_ARGS(SkPicture, (src.width(), src.height(), record.detach(), NULL/*bbh*/));
+    return SkNEW_ARGS(SkPicture, (src.cullRect().width(), src.cullRect().height(), 
+                                  record.detach(), NULL/*bbh*/));
 }
 
 // fRecord OK
@@ -447,7 +496,7 @@
         if (NULL == data) {
             return NULL;
         }
-        const SkPicture src(data, info.fWidth, info.fHeight);
+        const SkPicture src(data, info.fCullRect.width(), info.fCullRect.height());
         return Forwardport(src);
     }
 
@@ -458,7 +507,7 @@
 SkPicture* SkPicture::CreateFromBuffer(SkReadBuffer& buffer) {
     SkPictInfo info;
 
-    if (!InternalOnly_BufferIsSKP(buffer, &info)) {
+    if (!InternalOnly_BufferIsSKP(&buffer, &info)) {
         return NULL;
     }
 
@@ -468,7 +517,7 @@
         if (NULL == data) {
             return NULL;
         }
-        const SkPicture src(data, info.fWidth, info.fHeight);
+        const SkPicture src(data, info.fCullRect.width(), info.fCullRect.height());
         return Forwardport(src);
     }
 
@@ -484,8 +533,7 @@
 
     // Set picture info after magic bytes in the header
     info->fVersion = CURRENT_PICTURE_VERSION;
-    info->fWidth = fWidth;
-    info->fHeight = fHeight;
+    info->fCullRect = this->cullRect();
     info->fFlags = SkPictInfo::kCrossProcess_Flag;
     // TODO: remove this flag, since we're always float (now)
     info->fFlags |= SkPictInfo::kScalarIsFloat_Flag;
@@ -502,13 +550,14 @@
     // If we're a new-format picture, backport to old format for serialization.
     SkAutoTDelete<SkPicture> oldFormat;
     if (NULL == data && NULL != fRecord.get()) {
-        oldFormat.reset(backport(*fRecord, fWidth, fHeight));
+        oldFormat.reset(backport(*fRecord, this->cullRect()));
         data = oldFormat->fData.get();
         SkASSERT(NULL != data);
     }
 
     SkPictInfo info;
     this->createHeader(&info);
+    SkASSERT(sizeof(SkPictInfo) == 32);
     stream->write(&info, sizeof(info));
 
     if (NULL != data) {
@@ -526,14 +575,17 @@
     // If we're a new-format picture, backport to old format for serialization.
     SkAutoTDelete<SkPicture> oldFormat;
     if (NULL == data && NULL != fRecord.get()) {
-        oldFormat.reset(backport(*fRecord, fWidth, fHeight));
+        oldFormat.reset(backport(*fRecord, this->cullRect()));
         data = oldFormat->fData.get();
         SkASSERT(NULL != data);
     }
 
     SkPictInfo info;
     this->createHeader(&info);
-    buffer.writeByteArray(&info, sizeof(info));
+    buffer.writeByteArray(&info.fMagic, sizeof(info.fMagic));
+    buffer.writeUInt(info.fVersion);
+    buffer.writeRect(info.fCullRect);
+    buffer.writeUInt(info.fFlags);
 
     if (NULL != data) {
         buffer.writeBool(true);
@@ -605,9 +657,9 @@
 }
 
 // fRecord OK
-SkPicture::SkPicture(int width, int height, SkRecord* record, SkBBoxHierarchy* bbh)
-    : fWidth(width)
-    , fHeight(height)
+SkPicture::SkPicture(SkScalar width, SkScalar height, SkRecord* record, SkBBoxHierarchy* bbh)
+    : fCullWidth(width)
+    , fCullHeight(height)
     , fRecord(record)
     , fBBH(SkSafeRef(bbh))
     , fAnalysis(*record) {
diff --git a/src/core/SkPictureData.h b/src/core/SkPictureData.h
index a5f1ae0..019bfb2 100644
--- a/src/core/SkPictureData.h
+++ b/src/core/SkPictureData.h
@@ -37,8 +37,7 @@
 
     char        fMagic[8];
     uint32_t    fVersion;
-    uint32_t    fWidth;
-    uint32_t    fHeight;
+    SkRect      fCullRect;
     uint32_t    fFlags;
 };
 
diff --git a/src/core/SkPictureRecorder.cpp b/src/core/SkPictureRecorder.cpp
index d90f885..fadb937 100644
--- a/src/core/SkPictureRecorder.cpp
+++ b/src/core/SkPictureRecorder.cpp
@@ -17,7 +17,7 @@
 
 SkPictureRecorder::~SkPictureRecorder() {}
 
-SkCanvas* SkPictureRecorder::beginRecording(int width, int height,
+SkCanvas* SkPictureRecorder::beginRecording(SkScalar width, SkScalar height,
                                             SkBBHFactory* bbhFactory /* = NULL */,
                                             uint32_t recordFlags /* = 0 */) {
 #ifdef SK_PICTURE_USE_SK_RECORD
@@ -27,11 +27,11 @@
 #endif
 }
 
-SkCanvas* SkPictureRecorder::DEPRECATED_beginRecording(int width, int height,
+SkCanvas* SkPictureRecorder::DEPRECATED_beginRecording(SkScalar width, SkScalar height,
                                                        SkBBHFactory* bbhFactory /* = NULL */,
                                                        uint32_t recordFlags /* = 0 */) {
-    fWidth = width;
-    fHeight = height;
+    fCullWidth = width;
+    fCullHeight = height;
 
     const SkISize size = SkISize::Make(width, height);
 
@@ -49,10 +49,10 @@
     return this->getRecordingCanvas();
 }
 
-SkCanvas* SkPictureRecorder::EXPERIMENTAL_beginRecording(int width, int height,
+SkCanvas* SkPictureRecorder::EXPERIMENTAL_beginRecording(SkScalar width, SkScalar height,
                                                          SkBBHFactory* bbhFactory /* = NULL */) {
-    fWidth = width;
-    fHeight = height;
+    fCullWidth = width;
+    fCullHeight = height;
 
     if (NULL != bbhFactory) {
         fBBH.reset((*bbhFactory)(width, height));
@@ -75,13 +75,15 @@
     SkPicture* picture = NULL;
 
     if (NULL != fRecord.get()) {
-        picture = SkNEW_ARGS(SkPicture, (fWidth, fHeight, fRecord.detach(), fBBH.get()));
+        picture = SkNEW_ARGS(SkPicture, (fCullWidth, fCullHeight, 
+                                         fRecord.detach(), fBBH.get()));
     }
 
     if (NULL != fPictureRecord.get()) {
         fPictureRecord->endRecording();
         const bool deepCopyOps = false;
-        picture = SkNEW_ARGS(SkPicture, (fWidth, fHeight, *fPictureRecord.get(), deepCopyOps));
+        picture = SkNEW_ARGS(SkPicture, (fCullWidth, fCullHeight, 
+                                         *fPictureRecord.get(), deepCopyOps));
     }
 
     return picture;
@@ -104,7 +106,8 @@
 
     if (NULL != fPictureRecord.get()) {
         const bool deepCopyOps = true;
-        SkPicture picture(fWidth, fHeight, *fPictureRecord.get(), deepCopyOps);
+        SkPicture picture(fCullWidth, fCullHeight, 
+                          *fPictureRecord.get(), deepCopyOps);
         picture.draw(canvas);
     }
 }
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index 3e0eb65..73ab170 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -22,10 +22,9 @@
                                  const SkMatrix* localMatrix, const SkRect* tile)
     : INHERITED(localMatrix)
     , fPicture(SkRef(picture))
+    , fTile(NULL != tile ? *tile : picture->cullRect())
     , fTmx(tmx)
     , fTmy(tmy) {
-    fTile = tile ? *tile : SkRect::MakeWH(SkIntToScalar(picture->width()),
-                                          SkIntToScalar(picture->height()));
 }
 
 #ifdef SK_SUPPORT_LEGACY_DEEPFLATTENING
@@ -43,8 +42,7 @@
 
 SkPictureShader* SkPictureShader::Create(const SkPicture* picture, TileMode tmx, TileMode tmy,
                                          const SkMatrix* localMatrix, const SkRect* tile) {
-    if (!picture || 0 == picture->width() || 0 == picture->height()
-        || (NULL != tile && tile->isEmpty())) {
+    if (!picture || picture->cullRect().isEmpty() || (NULL != tile && tile->isEmpty())) {
         return NULL;
     }
     return SkNEW_ARGS(SkPictureShader, (picture, tmx, tmy, localMatrix, tile));
@@ -70,7 +68,7 @@
 }
 
 SkShader* SkPictureShader::refBitmapShader(const SkMatrix& matrix, const SkMatrix* localM) const {
-    SkASSERT(fPicture && fPicture->width() > 0 && fPicture->height() > 0);
+    SkASSERT(fPicture && !fPicture->cullRect().isEmpty());
 
     SkMatrix m;
     m.setConcat(matrix, this->getLocalMatrix());
@@ -201,9 +199,11 @@
         "clamp", "repeat", "mirror"
     };
 
-    str->appendf("PictureShader: [%d:%d] ",
-                 fPicture ? fPicture->width() : 0,
-                 fPicture ? fPicture->height() : 0);
+    str->appendf("PictureShader: [%f:%f:%f:%f] ",
+                 fPicture ? fPicture->cullRect().fLeft : 0,
+                 fPicture ? fPicture->cullRect().fTop : 0,
+                 fPicture ? fPicture->cullRect().fRight : 0,
+                 fPicture ? fPicture->cullRect().fBottom : 0);
 
     str->appendf("(%s, %s)", gTileModeName[fTmx], gTileModeName[fTmy]);
 
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 7985e2b..0117ade 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -321,7 +321,7 @@
     }
 
     Bounds bounds(const DrawPicture& op) const {
-        SkRect dst = SkRect::MakeWH(op.picture->width(), op.picture->height());
+        SkRect dst = op.picture->cullRect();
         if (op.matrix) {
             op.matrix->mapRect(&dst);
         }