add drawPicture variant that takes a matrix and paint

will need some staging strategy, since chrome and blink have overrides of onDrawPicture

R=robertphillips@google.com, fmalita@google.com, bsalomon@google.com, mtklein@google.com

Author: reed@google.com

Review URL: https://codereview.chromium.org/448793004
diff --git a/experimental/PdfViewer/SkNulCanvas.h b/experimental/PdfViewer/SkNulCanvas.h
index a976ea4..816b089 100644
--- a/experimental/PdfViewer/SkNulCanvas.h
+++ b/experimental/PdfViewer/SkNulCanvas.h
@@ -103,7 +103,7 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE {}
     virtual void onClipRegion(const SkRegion&, SkRegion::Op)  SK_OVERRIDE {}
 
-    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE {}
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE {}
     
 private:
     typedef SkCanvas INHERITED;
diff --git a/gm/picture.cpp b/gm/picture.cpp
new file mode 100644
index 0000000..1f7e5c3
--- /dev/null
+++ b/gm/picture.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "gm.h"
+#include "SkPaint.h"
+#include "SkPictureRecorder.h"
+
+static SkPicture* make_picture() {
+    SkPictureRecorder rec;
+    SkCanvas* canvas = rec.beginRecording(100, 100);
+
+    SkPaint paint;
+    paint.setAntiAlias(true);
+    SkPath path;
+
+    paint.setColor(0x800000FF);
+    canvas->drawRect(SkRect::MakeWH(100, 100), paint);
+
+    paint.setColor(0x80FF0000);
+    path.moveTo(0, 0); path.lineTo(100, 0); path.lineTo(100, 100);
+    canvas->drawPath(path, paint);
+    
+    paint.setColor(0x8000FF00);
+    path.reset(); path.moveTo(0, 0); path.lineTo(100, 0); path.lineTo(0, 100);
+    canvas->drawPath(path, paint);
+
+    paint.setColor(0x80FFFFFF);
+    paint.setXfermodeMode(SkXfermode::kPlus_Mode);
+    canvas->drawRect(SkRect::MakeXYWH(25, 25, 50, 50), paint);
+
+    return rec.endRecording();
+}
+
+// Exercise the optional arguments to drawPicture
+//
+class PictureGM : public skiagm::GM {
+public:
+    PictureGM() : fPicture(make_picture()) {}
+
+protected:
+    virtual SkString onShortName() SK_OVERRIDE {
+        return SkString("pictures");
+    }
+
+    virtual SkISize onISize() SK_OVERRIDE {
+        return SkISize::Make(450, 120);
+    }
+
+    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+        canvas->translate(10, 10);
+
+        SkMatrix matrix;
+        SkPaint paint;
+
+        canvas->drawPicture(fPicture);
+        
+        matrix.setTranslate(110, 0);
+        canvas->drawPicture(fPicture, &matrix, NULL);
+        
+        matrix.postTranslate(110, 0);
+        canvas->drawPicture(fPicture, &matrix, &paint);
+
+        paint.setAlpha(0x80);
+        matrix.postTranslate(110, 0);
+        canvas->drawPicture(fPicture, &matrix, &paint);
+    }
+
+private:
+    SkAutoTUnref<SkPicture> fPicture;
+
+    typedef skiagm::GM INHERITED;
+};
+
+DEF_GM( return SkNEW(PictureGM); )
diff --git a/gyp/gmslides.gypi b/gyp/gmslides.gypi
index c55da89..fbd2462 100644
--- a/gyp/gmslides.gypi
+++ b/gyp/gmslides.gypi
@@ -134,6 +134,7 @@
         '../gm/pathreverse.cpp',
         '../gm/peekpixels.cpp',
         '../gm/perlinnoise.cpp',
+        '../gm/picture.cpp',
         '../gm/pictureimagefilter.cpp',
         '../gm/pictureshader.cpp',
         '../gm/pictureshadertile.cpp',
diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h
index eef9d90..791511e 100644
--- a/include/core/SkCanvas.h
+++ b/include/core/SkCanvas.h
@@ -973,6 +973,20 @@
     */
     void drawPicture(const SkPicture* picture);
 
+    /**
+     *  Draw the picture into this canvas.
+     *
+     *  If matrix is non-null, apply that matrix to the CTM when drawing this picture. This is
+     *  logically equivalent to
+     *      save/concat/drawPicture/restore
+     *
+     *  If paint is non-null, draw the picture into a temporary buffer, and then apply the paint's
+     *  alpha/colorfilter/imagefilter/xfermode to that buffer as it is drawn to the canvas.
+     *  This is logically equivalent to
+     *      saveLayer(paint)/drawPicture/restore
+     */
+    void drawPicture(const SkPicture*, const SkMatrix* matrix, const SkPaint* paint);
+
     enum VertexMode {
         kTriangles_VertexMode,
         kTriangleStrip_VertexMode,
@@ -1223,9 +1237,9 @@
 
     virtual void onDiscard();
 
-    virtual void onDrawPicture(const SkPicture* picture);
     // temporary, until we can migrate existing overrides in chrome
-    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) {}
+    virtual void onDrawPicture(const SkPicture*) {}
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*);
 
     // Returns the canvas to be used by DrawIter. Default implementation
     // returns this. Subclasses that encapsulate an indirect canvas may
diff --git a/include/core/SkDevice.h b/include/core/SkDevice.h
index a5682c2..3d79a65 100644
--- a/include/core/SkDevice.h
+++ b/include/core/SkDevice.h
@@ -348,7 +348,8 @@
      *  to perform some device-specific warm up tasks and then let SkCanvas
      *  perform the main rendering loop (by return false from here).
      */
-    virtual bool EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* picture);
+    virtual bool EXPERIMENTAL_drawPicture(SkCanvas*, const SkPicture*, const SkMatrix*,
+                                          const SkPaint*);
 
 private:
     friend class SkCanvas;
diff --git a/include/gpu/SkGpuDevice.h b/include/gpu/SkGpuDevice.h
index 5ff26f6..b856d66 100644
--- a/include/gpu/SkGpuDevice.h
+++ b/include/gpu/SkGpuDevice.h
@@ -143,7 +143,8 @@
     /**  PRIVATE / EXPERIMENTAL -- do not call */
     virtual void EXPERIMENTAL_optimize(const SkPicture* picture) SK_OVERRIDE;
     /**  PRIVATE / EXPERIMENTAL -- do not call */
-    virtual bool EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* picture) SK_OVERRIDE;
+    virtual bool EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* picture,
+                                          const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
 private:
     GrContext*      fContext;
diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h
index f37e9d8..435c569 100644
--- a/include/utils/SkDeferredCanvas.h
+++ b/include/utils/SkDeferredCanvas.h
@@ -194,7 +194,7 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
 
-    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE;
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
 public:
     class NotificationClient {
diff --git a/include/utils/SkDumpCanvas.h b/include/utils/SkDumpCanvas.h
index 53b9755..866b408 100644
--- a/include/utils/SkDumpCanvas.h
+++ b/include/utils/SkDumpCanvas.h
@@ -127,7 +127,7 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
 
-    virtual void onDrawPicture(const SkPicture*) SK_OVERRIDE;
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
     static const char* EdgeStyleToAAString(ClipEdgeStyle edgeStyle);
 
diff --git a/include/utils/SkLuaCanvas.h b/include/utils/SkLuaCanvas.h
index 5d8a973..3315d66 100644
--- a/include/utils/SkLuaCanvas.h
+++ b/include/utils/SkLuaCanvas.h
@@ -66,7 +66,7 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
 
-    virtual void onDrawPicture(const SkPicture*) SK_OVERRIDE;
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
 private:
     lua_State*  fL;
diff --git a/include/utils/SkNWayCanvas.h b/include/utils/SkNWayCanvas.h
index a4bfa88..8d2854d 100644
--- a/include/utils/SkNWayCanvas.h
+++ b/include/utils/SkNWayCanvas.h
@@ -82,7 +82,7 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
 
-    virtual void onDrawPicture(const SkPicture*) SK_OVERRIDE;
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
     class Iter;
 
diff --git a/include/utils/SkProxyCanvas.h b/include/utils/SkProxyCanvas.h
index d31806f..2e002cc 100644
--- a/include/utils/SkProxyCanvas.h
+++ b/include/utils/SkProxyCanvas.h
@@ -79,7 +79,9 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
 
-    virtual void onDrawPicture(const SkPicture*) SK_OVERRIDE;
+    // temporary until we can land and fix chrome
+    virtual void onDrawPicture(const SkPicture*) SK_OVERRIDE {}
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
 private:
     SkCanvas*   fProxy;
diff --git a/src/core/SkBBoxRecord.cpp b/src/core/SkBBoxRecord.cpp
index 802eb66..96e6500 100644
--- a/src/core/SkBBoxRecord.cpp
+++ b/src/core/SkBBoxRecord.cpp
@@ -293,10 +293,17 @@
     }
 }
 
-void SkBBoxRecord::onDrawPicture(const SkPicture* picture) {
-    if (picture->width() > 0 && picture->height() > 0 &&
-        this->transformBounds(SkRect::MakeWH(picture->width(), picture->height()), NULL)) {
-        this->INHERITED::onDrawPicture(picture);
+void SkBBoxRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                                 const SkPaint* paint) {
+    SkRect bounds = SkRect::MakeWH(SkIntToScalar(picture->width()),
+                                   SkIntToScalar(picture->height()));
+    // todo: wonder if we should allow passing an optional matrix to transformBounds so we don't
+    // end up transforming the rect twice.
+    if (matrix) {
+        matrix->mapRect(&bounds);
+    }
+    if (this->transformBounds(bounds, paint)) {
+        this->INHERITED::onDrawPicture(picture, matrix, paint);
     }
 }
 
diff --git a/src/core/SkBBoxRecord.h b/src/core/SkBBoxRecord.h
index d10626f..eafd9d4 100644
--- a/src/core/SkBBoxRecord.h
+++ b/src/core/SkBBoxRecord.h
@@ -67,7 +67,7 @@
                                 SkScalar constY, const SkPaint&) SK_OVERRIDE;
     virtual void onDrawTextOnPath(const void* text, size_t byteLength, const SkPath& path,
                                   const SkMatrix* matrix, const SkPaint&) SK_OVERRIDE;
-    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE;
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
     virtual void willSave() SK_OVERRIDE;
     virtual SaveLayerStrategy willSaveLayer(const SkRect*, const SkPaint*, SaveFlags) SK_OVERRIDE;
     virtual void willRestore() SK_OVERRIDE;
diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp
index cf7050f..c6b5739 100644
--- a/src/core/SkCanvas.cpp
+++ b/src/core/SkCanvas.cpp
@@ -7,6 +7,7 @@
 
 
 #include "SkCanvas.h"
+#include "SkCanvasPriv.h"
 #include "SkBitmapDevice.h"
 #include "SkDeviceImageFilterProxy.h"
 #include "SkDraw.h"
@@ -2397,22 +2398,32 @@
 
 void SkCanvas::drawPicture(const SkPicture* picture) {
     if (NULL != picture) {
-        this->onDrawPicture(picture);
+        this->onDrawPicture(picture, NULL, NULL);
     }
 }
 
-void SkCanvas::onDrawPicture(const SkPicture* picture) {
-    SkASSERT(NULL != picture);
+void SkCanvas::drawPicture(const SkPicture* picture, const SkMatrix* matrix, const SkPaint* paint) {
+    if (NULL != picture) {
+        if (matrix && matrix->isIdentity()) {
+            matrix = NULL;
+        }
+        this->onDrawPicture(picture, matrix, paint);
+    }
+}
 
+void SkCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                             const SkPaint* paint) {
     SkBaseDevice* device = this->getTopDevice();
     if (NULL != device) {
         // Canvas has to first give the device the opportunity to render
         // the picture itself.
-        if (device->EXPERIMENTAL_drawPicture(this, picture)) {
+        if (device->EXPERIMENTAL_drawPicture(this, picture, matrix, paint)) {
             return; // the device has rendered the entire picture
         }
     }
 
+    SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height());
+
     picture->draw(this);
 }
 
@@ -2511,3 +2522,29 @@
     }
     return SkNEW_ARGS(SkCanvas, (bitmap));
 }
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkAutoCanvasMatrixPaint::SkAutoCanvasMatrixPaint(SkCanvas* canvas, const SkMatrix* matrix,
+                                                 const SkPaint* paint, int width, int height)
+    : fCanvas(canvas)
+    , fSaveCount(canvas->getSaveCount())
+{
+    if (NULL != paint) {
+        SkRect bounds = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
+        if (matrix) {
+            matrix->mapRect(&bounds);
+        }
+        canvas->saveLayer(&bounds, paint);
+    } else if (NULL != matrix) {
+        canvas->save();
+    }
+    
+    if (NULL != matrix) {
+        canvas->concat(*matrix);
+    }
+}
+
+SkAutoCanvasMatrixPaint::~SkAutoCanvasMatrixPaint() {
+    fCanvas->restoreToCount(fSaveCount);
+}
diff --git a/src/core/SkCanvasPriv.h b/src/core/SkCanvasPriv.h
new file mode 100644
index 0000000..9f66baa
--- /dev/null
+++ b/src/core/SkCanvasPriv.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2014 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkCanvasPriv_DEFINED
+#define SkCanvasPriv_DEFINED
+
+#include "SkCanvas.h"
+
+class SkAutoCanvasMatrixPaint : SkNoncopyable {
+public:
+    SkAutoCanvasMatrixPaint(SkCanvas*, const SkMatrix*, const SkPaint*, int width, int height);
+    ~SkAutoCanvasMatrixPaint();
+
+private:
+    SkCanvas*   fCanvas;
+    int         fSaveCount;
+};
+
+#endif
diff --git a/src/core/SkDevice.cpp b/src/core/SkDevice.cpp
index e71500a..6ceaffe 100644
--- a/src/core/SkDevice.cpp
+++ b/src/core/SkDevice.cpp
@@ -147,7 +147,8 @@
     // The base class doesn't perform any analysis but derived classes may
 }
 
-bool SkBaseDevice::EXPERIMENTAL_drawPicture(SkCanvas* canvas, const SkPicture* picture) {
+bool SkBaseDevice::EXPERIMENTAL_drawPicture(SkCanvas*, const SkPicture*, const SkMatrix*,
+                                            const SkPaint*) {
     // The base class doesn't perform any accelerated picture rendering
     return false;
 }
diff --git a/src/core/SkPictureFlat.h b/src/core/SkPictureFlat.h
index 2be929b..a8f0db4 100644
--- a/src/core/SkPictureFlat.h
+++ b/src/core/SkPictureFlat.h
@@ -69,8 +69,9 @@
     POP_CULL,
     
     DRAW_PATCH, // could not add in aphabetical order
+    DRAW_PICTURE_MATRIX_PAINT,
 
-    LAST_DRAWTYPE_ENUM = DRAW_PATCH
+    LAST_DRAWTYPE_ENUM = DRAW_PICTURE_MATRIX_PAINT
 };
 
 // In the 'match' method, this constant will match any flavor of DRAW_BITMAP*
diff --git a/src/core/SkPicturePlayback.cpp b/src/core/SkPicturePlayback.cpp
index 59abe7c..fd359fe 100644
--- a/src/core/SkPicturePlayback.cpp
+++ b/src/core/SkPicturePlayback.cpp
@@ -319,6 +319,13 @@
         case DRAW_PICTURE:
             canvas->drawPicture(fPictureData->getPicture(reader));
             break;
+        case DRAW_PICTURE_MATRIX_PAINT: {
+            const SkPicture* pic = fPictureData->getPicture(reader);
+            SkMatrix matrix;
+            reader->readMatrix(&matrix);
+            const SkPaint* paint = fPictureData->getPaint(reader);
+            canvas->drawPicture(pic, &matrix, paint);
+        } break;
         case DRAW_POINTS: {
             const SkPaint& paint = *fPictureData->getPaint(reader);
             SkCanvas::PointMode mode = (SkCanvas::PointMode)reader->readInt();
diff --git a/src/core/SkPictureRecord.cpp b/src/core/SkPictureRecord.cpp
index 31a66ab..66aa46d 100644
--- a/src/core/SkPictureRecord.cpp
+++ b/src/core/SkPictureRecord.cpp
@@ -1387,7 +1387,8 @@
     this->validate(initialOffset, size);
 }
 
-void SkPictureRecord::onDrawPicture(const SkPicture* picture) {
+void SkPictureRecord::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                                    const SkPaint* paint) {
 
 #ifdef SK_COLLAPSE_MATRIX_CLIP_STATE
     fMCMgr.call(SkMatrixClipStateMgr::kOther_CallType);
@@ -1395,8 +1396,19 @@
 
     // op + picture index
     size_t size = 2 * kUInt32Size;
-    size_t initialOffset = this->addDraw(DRAW_PICTURE, &size);
-    this->addPicture(picture);
+    size_t initialOffset;
+
+    if (NULL == matrix && NULL == paint) {
+        initialOffset = this->addDraw(DRAW_PICTURE, &size);
+        this->addPicture(picture);
+    } else {
+        const SkMatrix& m = matrix ? *matrix : SkMatrix::I();
+        size += m.writeToMemory(NULL) + kUInt32Size;    // matrix + paint
+        initialOffset = this->addDraw(DRAW_PICTURE_MATRIX_PAINT, &size);
+        this->addPicture(picture);
+        this->addMatrix(m);
+        this->addPaintPtr(paint);
+    }
     this->validate(initialOffset, size);
 }
 
diff --git a/src/core/SkPictureRecord.h b/src/core/SkPictureRecord.h
index 57e6008..21c1197 100644
--- a/src/core/SkPictureRecord.h
+++ b/src/core/SkPictureRecord.h
@@ -261,7 +261,7 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
 
-    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE;
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
     // Return fontmetrics.fTop,fBottom in topbot[0,1], after they have been
     // tweaked by paint.computeFastBounds().
diff --git a/src/core/SkRecordDraw.cpp b/src/core/SkRecordDraw.cpp
index 5af00b6..d29e0b8 100644
--- a/src/core/SkRecordDraw.cpp
+++ b/src/core/SkRecordDraw.cpp
@@ -52,7 +52,7 @@
 DRAW(DrawPaint, drawPaint(r.paint));
 DRAW(DrawPath, drawPath(r.path, r.paint));
 DRAW(DrawPatch, drawPatch(r.patch, r.paint));
-DRAW(DrawPicture, drawPicture(r.picture));
+DRAW(DrawPicture, drawPicture(r.picture, r.matrix, r.paint));
 DRAW(DrawPoints, drawPoints(r.mode, r.count, r.pts, r.paint));
 DRAW(DrawPosText, drawPosText(r.text, r.byteLength, r.pos, r.paint));
 DRAW(DrawPosTextH, drawPosTextH(r.text, r.byteLength, r.xpos, r.y, r.paint));
diff --git a/src/core/SkRecorder.cpp b/src/core/SkRecorder.cpp
index 19d60d5..6b3eac9 100644
--- a/src/core/SkRecorder.cpp
+++ b/src/core/SkRecorder.cpp
@@ -186,8 +186,8 @@
            this->copy(matrix));
 }
 
-void SkRecorder::onDrawPicture(const SkPicture* picture) {
-    APPEND(DrawPicture, picture);
+void SkRecorder::onDrawPicture(const SkPicture* pic, const SkMatrix* matrix, const SkPaint* paint) {
+    APPEND(DrawPicture, this->copy(paint), pic, this->copy(matrix));
 }
 
 void SkRecorder::drawVertices(VertexMode vmode,
diff --git a/src/core/SkRecorder.h b/src/core/SkRecorder.h
index 4371138..be89248 100644
--- a/src/core/SkRecorder.h
+++ b/src/core/SkRecorder.h
@@ -95,7 +95,7 @@
     void onClipPath(const SkPath& path, SkRegion::Op op, ClipEdgeStyle edgeStyle) SK_OVERRIDE;
     void onClipRegion(const SkRegion& deviceRgn, SkRegion::Op op) SK_OVERRIDE;
 
-    void onDrawPicture(const SkPicture* picture) SK_OVERRIDE;
+    void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
     void onPushCull(const SkRect& cullRect) SK_OVERRIDE;
     void onPopCull() SK_OVERRIDE;
diff --git a/src/core/SkRecords.h b/src/core/SkRecords.h
index 347bc36..6aefd19 100644
--- a/src/core/SkRecords.h
+++ b/src/core/SkRecords.h
@@ -14,17 +14,14 @@
 class SkPictureBox {
 public:
     SkPictureBox(const SkPicture* obj) : fObj(SkRef(obj)) {}
-    SkPictureBox(const SkPictureBox& src) : fObj(SkRef(src.fObj)) {}
     ~SkPictureBox() { fObj->unref(); }
 
-    SkPictureBox& operator=(const SkPictureBox& src) {
-        SkRefCnt_SafeAssign(fObj, src.fObj);
-        return *this;
-    }
-
     operator const SkPicture*() const { return fObj; }
 
 private:
+    SkPictureBox(const SkPictureBox&);
+    SkPictureBox& operator=(const SkPictureBox&);
+
     const SkPicture* fObj;
 };
 
@@ -236,7 +233,7 @@
 RECORD1(DrawPaint, SkPaint, paint);
 RECORD2(DrawPath, SkPaint, paint, SkPath, path);
 RECORD2(DrawPatch, SkPaint, paint, SkPatch, patch);
-RECORD1(DrawPicture, SkPictureBox, picture);
+RECORD3(DrawPicture, Optional<SkPaint>, paint, SkPictureBox, picture, Optional<SkMatrix>, matrix);
 RECORD4(DrawPoints, SkPaint, paint, SkCanvas::PointMode, mode, size_t, count, SkPoint*, pts);
 RECORD4(DrawPosText, SkPaint, paint,
                      PODArray<char>, text,
diff --git a/src/gpu/GrPictureUtils.cpp b/src/gpu/GrPictureUtils.cpp
index 0bcd927..6e3c6b7 100644
--- a/src/gpu/GrPictureUtils.cpp
+++ b/src/gpu/GrPictureUtils.cpp
@@ -6,6 +6,7 @@
  */
 
 #include "GrPictureUtils.h"
+#include "SkCanvasPriv.h"
 #include "SkDevice.h"
 #include "SkDraw.h"
 #include "SkPaintPriv.h"
@@ -234,7 +235,10 @@
         this->updateClipConservativelyUsingBounds(rrect.getBounds(), op, false);
     }
 
-    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE {
+    virtual void onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                               const SkPaint* paint) SK_OVERRIDE {
+        SkAutoCanvasMatrixPaint acmp(this, matrix, paint, picture->width(), picture->height());
+
         if (NULL != picture->fData.get()) {
             // Disable the BBH for the old path so all the draw calls
             // will be seen. The stock SkPicture::draw method can't be
diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp
index 3ba2abc..3e6bf1b 100644
--- a/src/gpu/SkGpuDevice.cpp
+++ b/src/gpu/SkGpuDevice.cpp
@@ -1872,7 +1872,13 @@
     result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref();
 }
 
-bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* picture) {
+bool SkGpuDevice::EXPERIMENTAL_drawPicture(SkCanvas* mainCanvas, const SkPicture* picture,
+                                           const SkMatrix* matrix, const SkPaint* paint) {
+    // todo: should handle these natively
+    if (matrix || paint) {
+        return false;
+    }
+
     fContext->getLayerCache()->processDeletedPictures();
 
     SkPicture::AccelData::Key key = GPUAccelData::ComputeAccelDataKey();
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 186b66c..d796e8a 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -289,7 +289,7 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRegion(const SkRegion&, SkRegion::Op) SK_OVERRIDE;
 
-    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE;
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
 private:
     void recordTranslate(const SkMatrix&);
@@ -933,9 +933,14 @@
     }
 }
 
-void SkGPipeCanvas::onDrawPicture(const SkPicture* picture) {
+void SkGPipeCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                                  const SkPaint* paint) {
     // we want to playback the picture into individual draw calls
-    this->INHERITED::onDrawPicture(picture);
+    //
+    // todo: do we always have to unroll? If the pipe is not cross-process, seems like
+    // we could just ref the picture and move on...? <reed, scroggo>
+    //
+    this->INHERITED::onDrawPicture(picture, matrix, paint);
 }
 
 void SkGPipeCanvas::drawVertices(VertexMode vmode, int vertexCount,
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 17a1f6c..128f8a5 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -899,8 +899,9 @@
     this->recordedDrawCommand();
 }
 
-void SkDeferredCanvas::onDrawPicture(const SkPicture* picture) {
-    this->drawingCanvas()->drawPicture(picture);
+void SkDeferredCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                                     const SkPaint* paint) {
+    this->drawingCanvas()->drawPicture(picture, matrix, paint);
     this->recordedDrawCommand();
 }
 
diff --git a/src/utils/SkDumpCanvas.cpp b/src/utils/SkDumpCanvas.cpp
index 3c683e6..946aaa3 100644
--- a/src/utils/SkDumpCanvas.cpp
+++ b/src/utils/SkDumpCanvas.cpp
@@ -422,11 +422,12 @@
                str.c_str(), byteLength);
 }
 
-void SkDumpCanvas::onDrawPicture(const SkPicture* picture) {
+void SkDumpCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                                 const SkPaint* paint) {
     this->dump(kDrawPicture_Verb, NULL, "drawPicture(%p) %d:%d", picture,
                picture->width(), picture->height());
     fNestLevel += 1;
-    this->INHERITED::onDrawPicture(picture);
+    this->INHERITED::onDrawPicture(picture, matrix, paint);
     fNestLevel -= 1;
     this->dump(kDrawPicture_Verb, NULL, "endPicture(%p) %d:%d", &picture,
                picture->width(), picture->height());
diff --git a/src/utils/SkLuaCanvas.cpp b/src/utils/SkLuaCanvas.cpp
index b0b9128..0903ee8 100644
--- a/src/utils/SkLuaCanvas.cpp
+++ b/src/utils/SkLuaCanvas.cpp
@@ -268,10 +268,11 @@
     lua.pushPaint(paint, "paint");
 }
 
-void SkLuaCanvas::onDrawPicture(const SkPicture* picture) {
+void SkLuaCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                                const SkPaint* paint) {
     AUTO_LUA("drawPicture");
     // call through so we can see the nested picture ops
-    this->INHERITED::onDrawPicture(picture);
+    this->INHERITED::onDrawPicture(picture, matrix, paint);
 }
 
 void SkLuaCanvas::drawVertices(VertexMode vmode, int vertexCount,
diff --git a/src/utils/SkNWayCanvas.cpp b/src/utils/SkNWayCanvas.cpp
index b33c99e..d02835a 100644
--- a/src/utils/SkNWayCanvas.cpp
+++ b/src/utils/SkNWayCanvas.cpp
@@ -265,10 +265,11 @@
     }
 }
 
-void SkNWayCanvas::onDrawPicture(const SkPicture* picture) {
+void SkNWayCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                                 const SkPaint* paint) {
     Iter iter(fList);
     while (iter.next()) {
-        iter->drawPicture(picture);
+        iter->drawPicture(picture, matrix, paint);
     }
 }
 
diff --git a/src/utils/SkProxyCanvas.cpp b/src/utils/SkProxyCanvas.cpp
index 1029f40..773fd20 100644
--- a/src/utils/SkProxyCanvas.cpp
+++ b/src/utils/SkProxyCanvas.cpp
@@ -136,8 +136,9 @@
     fProxy->drawTextOnPath(text, byteLength, path, matrix, paint);
 }
 
-void SkProxyCanvas::onDrawPicture(const SkPicture* picture) {
-    fProxy->drawPicture(picture);
+void SkProxyCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix* matrix,
+                                  const SkPaint* paint) {
+    fProxy->drawPicture(picture, matrix, paint);
 }
 
 void SkProxyCanvas::drawVertices(VertexMode vmode, int vertexCount,
diff --git a/src/utils/debugger/SkDebugCanvas.cpp b/src/utils/debugger/SkDebugCanvas.cpp
index 277e86d..516d582 100644
--- a/src/utils/debugger/SkDebugCanvas.cpp
+++ b/src/utils/debugger/SkDebugCanvas.cpp
@@ -519,7 +519,8 @@
     this->addDrawCommand(new SkDrawPathCommand(path, paint));
 }
 
-void SkDebugCanvas::onDrawPicture(const SkPicture* picture) {
+void SkDebugCanvas::onDrawPicture(const SkPicture* picture, const SkMatrix*, const SkPaint*) {
+    // todo: add matrix and paint to SkDrawPictureCommand
     this->addDrawCommand(new SkDrawPictureCommand(picture));
 }
 
diff --git a/src/utils/debugger/SkDebugCanvas.h b/src/utils/debugger/SkDebugCanvas.h
index 50a9152..e774121 100644
--- a/src/utils/debugger/SkDebugCanvas.h
+++ b/src/utils/debugger/SkDebugCanvas.h
@@ -255,7 +255,7 @@
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRegion(const SkRegion& region, SkRegion::Op) SK_OVERRIDE;
 
-    virtual void onDrawPicture(const SkPicture* picture) SK_OVERRIDE;
+    virtual void onDrawPicture(const SkPicture*, const SkMatrix*, const SkPaint*) SK_OVERRIDE;
 
     void markActiveCommands(int index);