initial preroll api

BUG=skia:

Review URL: https://codereview.chromium.org/855473002
diff --git a/gyp/core.gypi b/gyp/core.gypi
index 4822851..e756728 100644
--- a/gyp/core.gypi
+++ b/gyp/core.gypi
@@ -145,6 +145,7 @@
         '<(skia_src_path)/core/SkPictureFlat.h',
         '<(skia_src_path)/core/SkPicturePlayback.cpp',
         '<(skia_src_path)/core/SkPicturePlayback.h',
+        '<(skia_src_path)/core/SkPicturePreroll.cpp',
         '<(skia_src_path)/core/SkPictureRecord.cpp',
         '<(skia_src_path)/core/SkPictureRecord.h',
         '<(skia_src_path)/core/SkPictureRecorder.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index 4e7ed30..3eecaf7 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -87,7 +87,7 @@
      *  by any device/pixels. Typically this use used by subclasses who handle
      *  the draw calls in some other way.
      */
-    SkCanvas(int width, int height);
+    SkCanvas(int width, int height, const SkSurfaceProps* = NULL);
 
     /** Construct a canvas with the specified device to draw into.
 
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index b0587b2..f59042c 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -131,6 +131,8 @@
      */
     SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps* = NULL) const;
 
+    void preroll() const;
+
     const char* toString(SkString*) const;
 
     /**
diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h
index 5b2f7a9..5a48476 100644
--- a/include/core/SkPicture.h
+++ b/include/core/SkPicture.h
@@ -171,6 +171,22 @@
      */
     bool willPlayBackBitmaps() const;
 
+    /**
+     *  This is a general hint that the picture will (soon) be drawn into a SkCanvas with
+     *  corresponding attributes (e.g. clip, matrix, props). No drawing occurs, but some
+     *  expensive operations may be run (e.g. image decoding).
+     *
+     *  Any of the parameters may be NULL.
+     *
+     *  @param srcBounds If not NULL, this is the subset of the picture (in the same coordinates
+     *                   as the picture's bounds) that preroll() should focus on.
+     *  @param initialMatrix If not NULL, this is the initialMatrix that is expected when the
+     *                       picture is actually drawn.
+     *  @param props If not NULL, these are the expected props when the picture is actually drawn.
+     */
+    void preroll(const SkRect* srcBounds, const SkMatrix* initialMatrix, const SkSurfaceProps*,
+                 void* gpuCacheAccessor) const;
+
     /** Return true if the SkStream/Buffer represents a serialized picture, and
         fills out SkPictInfo. After this function returns, the data source is not
         rewound so it will have to be manually reset before passing to
diff --git a/include/core/SkShader.h b/include/core/SkShader.h
index f8de276..1ae531e 100644
--- a/include/core/SkShader.h
+++ b/include/core/SkShader.h
@@ -478,6 +478,8 @@
      */
     virtual SkShader* refAsALocalMatrixShader(SkMatrix* localMatrix) const;
 
+    void preroll() const { this->onPreroll(); }
+
     SK_TO_STRING_VIRT()
     SK_DEFINE_FLATTENABLE_TYPE(SkShader)
 
@@ -492,6 +494,7 @@
      */
     virtual Context* onCreateContext(const ContextRec&, void* storage) const;
 
+    virtual void onPreroll() const {}
     virtual bool onAsLuminanceColor(SkColor*) const {
         return false;
     }
diff --git a/samplecode/SampleApp.cpp b/samplecode/SampleApp.cpp
index 105976d..aa2130e 100644
--- a/samplecode/SampleApp.cpp
+++ b/samplecode/SampleApp.cpp
@@ -1340,6 +1340,10 @@
         SkAutoTUnref<const SkPicture> picture(fRecorder.endRecording());
 
         if (true) {
+            picture->preroll(NULL, NULL, NULL, NULL);
+        }
+
+        if (true) {
             this->installDrawFilter(orig);
             
             if (true) {
diff --git a/src/core/SkBitmapProcShader.cpp b/src/core/SkBitmapProcShader.cpp
index 456e0d4..e6ed113 100644
--- a/src/core/SkBitmapProcShader.cpp
+++ b/src/core/SkBitmapProcShader.cpp
@@ -112,6 +112,12 @@
     return sizeof(BitmapProcShaderContext) + sizeof(SkBitmapProcState);
 }
 
+void SkBitmapProcShader::onPreroll() const {
+    SkBitmap bm(fRawBitmap);
+    bm.lockPixels();
+    bm.unlockPixels();
+}
+
 SkBitmapProcShader::BitmapProcShaderContext::BitmapProcShaderContext(
         const SkBitmapProcShader& shader, const ContextRec& rec, SkBitmapProcState* state)
     : INHERITED(shader, rec)
diff --git a/src/core/SkBitmapProcShader.h b/src/core/SkBitmapProcShader.h
index f73d56f..dc36154 100644
--- a/src/core/SkBitmapProcShader.h
+++ b/src/core/SkBitmapProcShader.h
@@ -57,6 +57,7 @@
 protected:
     void flatten(SkWriteBuffer&) const SK_OVERRIDE;
     Context* onCreateContext(const ContextRec&, void* storage) const SK_OVERRIDE;
+    void onPreroll() const SK_OVERRIDE;
 
     SkBitmap    fRawBitmap;   // experimental for RLE encoding
     uint8_t     fTileModeX, fTileModeY;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index 13b84e7..5b37e08 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -482,9 +482,9 @@
     typedef SkBitmapDevice INHERITED;
 };
 
-SkCanvas::SkCanvas(int width, int height)
+SkCanvas::SkCanvas(int width, int height, const SkSurfaceProps* props)
     : fMCStack(sizeof(MCRec), fMCRecStorage, sizeof(fMCRecStorage))
-    , fProps(SkSurfaceProps::kLegacyFontHost_InitType)
+    , fProps(SkSurfacePropsCopyOrDefault(props))
 {
     inc_canvas();
 
diff --git a/src/core/SkPicturePreroll.cpp b/src/core/SkPicturePreroll.cpp
new file mode 100644
index 0000000..b0a4b17
--- /dev/null
+++ b/src/core/SkPicturePreroll.cpp
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2015 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkCanvas.h"
+#include "SkPicture.h"
+
+class SkPrerollCanvas : public SkCanvas {
+public:
+    SkPrerollCanvas(int width, int height, const SkSurfaceProps* props)
+        : SkCanvas(width, height, props)
+    {}
+
+protected:
+    void onDrawDRRect(const SkRRect&, const SkRRect&, const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+    
+    void onDrawText(const void*, size_t, SkScalar, SkScalar, const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+    
+    void onDrawPosText(const void*, size_t, const SkPoint[], const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+    
+    void onDrawPosTextH(const void*, size_t, const SkScalar[], SkScalar,
+                        const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+    
+    void onDrawTextOnPath(const void*, size_t, const SkPath&, const SkMatrix*,
+                          const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+    
+    void onDrawTextBlob(const SkTextBlob*, SkScalar, SkScalar, const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+    
+    void onDrawPatch(const SkPoint[12], const SkColor[4], const SkPoint[4], SkXfermode*,
+                     const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+    
+    void onDrawPaint(const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+
+    void onDrawRect(const SkRect&, const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+
+    void onDrawOval(const SkRect&, const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+
+    void onDrawRRect(const SkRRect&, const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+
+    void onDrawPoints(PointMode, size_t, const SkPoint[], const SkPaint& paint) {
+        this->handlePaint(paint);
+    }
+
+    void onDrawVertices(VertexMode, int, const SkPoint[], const SkPoint[], const SkColor[],
+                        SkXfermode*, const uint16_t[], int, const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+
+    void onDrawPath(const SkPath&, const SkPaint& paint) SK_OVERRIDE {
+        this->handlePaint(paint);
+    }
+
+    void onDrawImage(const SkImage* image, SkScalar, SkScalar, const SkPaint* paint) SK_OVERRIDE {
+        this->handleImage(image);
+        if (paint) {
+            this->handlePaint(*paint);
+        }
+    }
+
+    void onDrawImageRect(const SkImage* image, const SkRect*, const SkRect&,
+                         const SkPaint* paint) SK_OVERRIDE {
+        this->handleImage(image);
+        if (paint) {
+            this->handlePaint(*paint);
+        }
+    }
+
+    void onDrawBitmap(const SkBitmap& bm, SkScalar, SkScalar, const SkPaint* paint) SK_OVERRIDE {
+        this->handleBitmap(bm);
+        if (paint) {
+            this->handlePaint(*paint);
+        }
+    }
+
+    void onDrawBitmapRect(const SkBitmap& bm, const SkRect*, const SkRect&, const SkPaint* paint,
+                          DrawBitmapRectFlags) SK_OVERRIDE {
+        this->handleBitmap(bm);
+        if (paint) {
+            this->handlePaint(*paint);
+        }
+    }
+
+    void onDrawBitmapNine(const SkBitmap& bm, const SkIRect&, const SkRect&,
+                          const SkPaint* paint) SK_OVERRIDE {
+        this->handleBitmap(bm);
+        if (paint) {
+            this->handlePaint(*paint);
+        }
+    }
+
+    void onDrawSprite(const SkBitmap& bm, int, int, const SkPaint* paint) SK_OVERRIDE {
+        this->handleBitmap(bm);
+        if (paint) {
+            this->handlePaint(*paint);
+        }
+    }
+
+private:
+    void handlePaint(const SkPaint& paint) {
+        const SkShader* shader = paint.getShader();
+        if (shader) {
+            shader->preroll();
+        }
+    }
+
+    void handleImage(const SkImage* image) {
+        image->preroll();
+    }
+
+    void handleBitmap(const SkBitmap& bitmap) {
+        SkBitmap bm(bitmap);
+        bm.lockPixels();
+    }
+
+    typedef SkCanvas INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+void SkPicture::preroll(const SkRect* srcBounds, const SkMatrix* initialMatrix,
+                        const SkSurfaceProps* props, void* gpuCacheAccessor) const {
+    SkRect bounds = this->cullRect();
+    if (srcBounds && !bounds.intersect(*srcBounds)) {
+        return;
+    }
+
+    const SkIRect ibounds = bounds.roundOut();
+    if (ibounds.isEmpty()) {
+        return;
+    }
+
+    SkPrerollCanvas canvas(ibounds.width(), ibounds.height(), props);
+
+    canvas.translate(-SkIntToScalar(ibounds.left()), -SkIntToScalar(ibounds.top()));
+    canvas.drawPicture(this, initialMatrix, NULL);
+}
+
diff --git a/src/core/SkPictureShader.cpp b/src/core/SkPictureShader.cpp
index 819a0d0..36b55ca 100644
--- a/src/core/SkPictureShader.cpp
+++ b/src/core/SkPictureShader.cpp
@@ -221,6 +221,10 @@
     return PictureShaderContext::Create(storage, *this, rec, bitmapShader);
 }
 
+void SkPictureShader::onPreroll() const {
+    fPicture->preroll(NULL, NULL, NULL, NULL);
+}
+
 /////////////////////////////////////////////////////////////////////////////////////////
 
 SkShader::Context* SkPictureShader::PictureShaderContext::Create(void* storage,
diff --git a/src/core/SkPictureShader.h b/src/core/SkPictureShader.h
index 8df9f53..7b07b851 100644
--- a/src/core/SkPictureShader.h
+++ b/src/core/SkPictureShader.h
@@ -37,6 +37,7 @@
     SkPictureShader(SkReadBuffer&);
     void flatten(SkWriteBuffer&) const SK_OVERRIDE;
     Context* onCreateContext(const ContextRec&, void* storage) const SK_OVERRIDE;
+    void onPreroll() const SK_OVERRIDE;
 
 private:
     SkPictureShader(const SkPicture*, TileMode, TileMode, const SkMatrix*, const SkRect*);
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index 1098088..35fff1f 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -118,6 +118,10 @@
     return as_IB(this)->onNewImage(newWidth, newHeight, subset, quality);
 }
 
+void SkImage::preroll() const {
+    as_IB(this)->onPreroll();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static bool raster_canvas_supports(const SkImageInfo& info) {
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index 512c80c..ca0559f 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -63,6 +63,8 @@
     virtual SkImage* onNewImage(int newWidth, int newHeight, const SkIRect* subset,
                                 SkFilterQuality) const;
 
+    virtual void onPreroll() const {}
+
 private:
     const SkSurfaceProps fProps;
 
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 1dd57d6..940d532 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -58,6 +58,7 @@
     bool onReadPixels(const SkImageInfo&, void*, size_t, int srcX, int srcY) const SK_OVERRIDE;
     const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const SK_OVERRIDE;
     bool getROPixels(SkBitmap*) const SK_OVERRIDE;
+    void onPreroll() const SK_OVERRIDE;
 
     // exposed for SkSurface_Raster via SkNewImageFromPixelRef
     SkImage_Raster(const SkImageInfo&, SkPixelRef*, size_t rowBytes, const SkSurfaceProps*);
@@ -154,6 +155,12 @@
     return true;
 }
 
+void SkImage_Raster::onPreroll() const {
+    SkBitmap bm(fBitmap);
+    bm.lockPixels();
+    bm.unlockPixels();
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 SkImage* SkImage::NewRasterCopy(const SkImageInfo& info, const void* pixels, size_t rowBytes) {
@@ -208,3 +215,4 @@
 bool SkImage_Raster::isOpaque() const {
     return fBitmap.isOpaque();
 }
+