Override SkCanvas::drawImage() in SkDeferredCanvas and SkGPipe

BUG=skia:2947

Review URL: https://codereview.chromium.org/613673005
diff --git a/include/utils/SkDeferredCanvas.h b/include/utils/SkDeferredCanvas.h
index 5f781f8..a1ac295 100644
--- a/include/utils/SkDeferredCanvas.h
+++ b/include/utils/SkDeferredCanvas.h
@@ -164,8 +164,12 @@
     virtual void drawBitmapMatrix(const SkBitmap& bitmap, const SkMatrix& m,
                                   const SkPaint* paint) SK_OVERRIDE;
     virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
-                                const SkRect& dst, const SkPaint* paint)
-                                SK_OVERRIDE;
+                                const SkRect& dst, const SkPaint* paint) SK_OVERRIDE;
+    virtual void drawImage(const SkImage* image, SkScalar left, SkScalar top,
+                           const SkPaint* paint) SK_OVERRIDE;
+    virtual void drawImageRect(const SkImage* image, const SkRect* src,
+                               const SkRect& dst,
+                               const SkPaint* paint) SK_OVERRIDE;
     virtual void drawSprite(const SkBitmap& bitmap, int left, int top,
                             const SkPaint* paint) SK_OVERRIDE;
     virtual void drawVertices(VertexMode vmode, int vertexCount,
@@ -197,7 +201,7 @@
     virtual void onDrawPatch(const SkPoint cubics[12], const SkColor colors[4],
                              const SkPoint texCoords[4], SkXfermode* xmode,
                              const SkPaint& paint) SK_OVERRIDE;
-    
+
     virtual void onClipRect(const SkRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipRRect(const SkRRect&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
     virtual void onClipPath(const SkPath&, SkRegion::Op, ClipEdgeStyle) SK_OVERRIDE;
diff --git a/src/pipe/SkGPipePriv.h b/src/pipe/SkGPipePriv.h
index 121512d..8d2a2af 100644
--- a/src/pipe/SkGPipePriv.h
+++ b/src/pipe/SkGPipePriv.h
@@ -46,6 +46,8 @@
     kDrawClear_DrawOp,
     kDrawData_DrawOp,
     kDrawDRRect_DrawOp,
+    kDrawImage_DrawOp,
+    kDrawImageRect_DrawOp,
     kDrawOval_DrawOp,
     kDrawPaint_DrawOp,
     kDrawPatch_DrawOp,
@@ -157,6 +159,10 @@
     kDrawBitmap_Bleed_DrawOpFlag      = 1 << 2,
 };
 enum {
+    kDrawImage_HasPaint_DrawOpFlag   = 1 << 0,
+    kDrawImage_HasSrcRect_DrawOpFlag = 1 << 1,
+};
+enum {
     kClip_HasAntiAlias_DrawOpFlag = 1 << 0,
 };
 ///////////////////////////////////////////////////////////////////////////////
diff --git a/src/pipe/SkGPipeRead.cpp b/src/pipe/SkGPipeRead.cpp
index 8cb0e34..222dc99 100644
--- a/src/pipe/SkGPipeRead.cpp
+++ b/src/pipe/SkGPipeRead.cpp
@@ -408,11 +408,11 @@
 
 static void drawPatch_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
                          SkGPipeState* state) {
-    
+
     unsigned flags = DrawOp_unpackFlags(op32);
-    
+
     const SkPoint* cubics = skip<SkPoint>(reader, SkPatchUtils::kNumCtrlPts);
-    
+
     const SkColor* colors = NULL;
     if (flags & kDrawVertices_HasColors_DrawOpFlag) {
         colors = skip<SkColor>(reader, SkPatchUtils::kNumCorners);
@@ -651,6 +651,40 @@
     }
 }
 
+static void drawImage_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
+                          SkGPipeState* state) {
+    bool hasPaint = SkToBool(DrawOp_unpackFlags(op32) & kDrawBitmap_HasPaint_DrawOpFlag);
+    // Balances call to ref() in SkGPipeWrite
+    SkAutoTUnref<const SkImage> image (static_cast<const SkImage*>(reader->readPtr()));
+
+    SkScalar left = reader->readScalar();
+    SkScalar top = reader->readScalar();
+
+    if (state->shouldDraw()) {
+        canvas->drawImage(image, left, top, hasPaint ? &state->paint() : NULL);
+    }
+}
+
+static void drawImageRect_rp(SkCanvas* canvas, SkReader32* reader,
+                              uint32_t op32, SkGPipeState* state) {
+    unsigned flags = DrawOp_unpackFlags(op32);
+    bool hasPaint = SkToBool(flags & kDrawBitmap_HasPaint_DrawOpFlag);
+    bool hasSrc = SkToBool(flags & kDrawBitmap_HasSrcRect_DrawOpFlag);
+    // Balances call to ref() in SkGPipeWrite
+    SkAutoTUnref<const SkImage> image (static_cast<const SkImage*>(reader->readPtr()));
+
+    const SkRect* src;
+    if (hasSrc) {
+        src = skip<SkRect>(reader);
+    } else {
+        src = NULL;
+    }
+    const SkRect* dst = skip<SkRect>(reader);
+    if (state->shouldDraw()) {
+        canvas->drawImageRect(image, src, *dst, hasPaint ? &state->paint() : NULL);
+    }
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static void drawData_rp(SkCanvas* canvas, SkReader32* reader, uint32_t op32,
@@ -831,6 +865,8 @@
     drawClear_rp,
     drawData_rp,
     drawDRRect_rp,
+    drawImage_rp,
+    drawImageRect_rp,
     drawOval_rp,
     drawPaint_rp,
     drawPatch_rp,
diff --git a/src/pipe/SkGPipeWrite.cpp b/src/pipe/SkGPipeWrite.cpp
index 41b0234..a1e7dc2 100644
--- a/src/pipe/SkGPipeWrite.cpp
+++ b/src/pipe/SkGPipeWrite.cpp
@@ -250,6 +250,11 @@
                                   const SkPaint*) SK_OVERRIDE;
     virtual void drawBitmapNine(const SkBitmap& bitmap, const SkIRect& center,
                                 const SkRect& dst, const SkPaint* paint = NULL) SK_OVERRIDE;
+    virtual void drawImage(const SkImage* image, SkScalar left, SkScalar top,
+                           const SkPaint* paint) SK_OVERRIDE;
+    virtual void drawImageRect(const SkImage* image, const SkRect* src,
+                               const SkRect& dst,
+                               const SkPaint* paint) SK_OVERRIDE;
     virtual void drawSprite(const SkBitmap&, int left, int top,
                             const SkPaint*) SK_OVERRIDE;
     virtual void drawVertices(VertexMode, int vertexCount,
@@ -359,6 +364,9 @@
     bool commonDrawBitmap(const SkBitmap& bm, DrawOps op, unsigned flags,
                           size_t opBytesNeeded, const SkPaint* paint);
 
+    bool commonDrawImage(const SkImage* image, DrawOps op, unsigned flags,
+                         size_t opBytesNeeded, const SkPaint* paint);
+
     SkPaint fPaint;
     void writePaint(const SkPaint&);
 
@@ -471,6 +479,7 @@
         }
     }
     fFlattenableHeap.setBitmapStorage(fBitmapHeap);
+
     this->doNotify();
 }
 
@@ -799,6 +808,79 @@
     return false;
 }
 
+bool SkGPipeCanvas::commonDrawImage(const SkImage* image, DrawOps op,
+                                    unsigned flags,
+                                    size_t opBytesNeeded,
+                                    const SkPaint* paint) {
+     if (fDone) {
+        return false;
+    }
+
+    if (paint != NULL) {
+        flags |= kDrawBitmap_HasPaint_DrawOpFlag;
+        this->writePaint(*paint);
+    }
+
+     opBytesNeeded += sizeof (SkImage*);
+
+    if (this->needOpBytes(opBytesNeeded)) {
+        this->writeOp(op, flags, 0);
+
+        image->ref(); // The SkGPipeReader will have to call unref()
+        fWriter.writePtr(static_cast<void*>(const_cast<SkImage*>(image)));
+
+        return true;
+    }
+    return false;
+}
+
+void SkGPipeCanvas::drawImage(const SkImage* image, SkScalar left, SkScalar top,
+                       const SkPaint* paint) {
+    if (is_cross_process(fFlags)){
+        // If the SkGPipe is cross-process, we will have to flatten the data in the SkImage, so
+        // fallback to the default implementation in SkCanvas (which calls SkImage::draw())
+        // https://code.google.com//p/skia/issues/detail?id=2985
+        this->INHERITED::drawImage(image, left, top, paint);
+    } else {
+        NOTIFY_SETUP(this);
+        size_t opBytesNeeded = sizeof(SkScalar) * 2;
+
+        if (this->commonDrawImage(image, kDrawImage_DrawOp, 0, opBytesNeeded, paint)) {
+            fWriter.writeScalar(left);
+            fWriter.writeScalar(top);
+        }
+    }
+}
+
+void SkGPipeCanvas::drawImageRect(const SkImage* image, const SkRect* src,
+                                  const SkRect& dst,
+                                  const SkPaint* paint) {
+    if (is_cross_process(fFlags)){
+        // If the SkGPipe is cross-process, we will have to flatten the data in the SkImage, so
+        // fallback to the default implementation in SkCanvas (which calls SkImage::drawRect())
+        // https://code.google.com//p/skia/issues/detail?id=2985
+       this->INHERITED::drawImageRect(image, src, dst, paint);
+    } else {
+        NOTIFY_SETUP(this);
+        size_t opBytesNeeded = sizeof (SkRect);
+        bool hasSrc = src != NULL;
+        unsigned flags;
+        if (hasSrc) {
+            flags = kDrawImage_HasSrcRect_DrawOpFlag;
+            opBytesNeeded += sizeof (SkRect);
+        } else {
+            flags = 0;
+        }
+
+        if (this->commonDrawImage(image, kDrawImageRect_DrawOp, flags, opBytesNeeded, paint)) {
+            if (hasSrc) {
+                fWriter.writeRect(*src);
+            }
+            fWriter.writeRect(dst);
+        }
+    }
+}
+
 void SkGPipeCanvas::drawBitmap(const SkBitmap& bm, SkScalar left, SkScalar top,
                                const SkPaint* paint) {
     NOTIFY_SETUP(this);
@@ -1090,7 +1172,7 @@
                                 const SkPoint texCoords[4], SkXfermode* xmode,
                                 const SkPaint& paint) {
     NOTIFY_SETUP(this);
-    
+
     size_t size = SkPatchUtils::kNumCtrlPts * sizeof(SkPoint);
     unsigned flags = 0;
     if (colors) {
@@ -1108,21 +1190,21 @@
             size += sizeof(int32_t);
         }
     }
-    
+
     this->writePaint(paint);
     if (this->needOpBytes(size)) {
         this->writeOp(kDrawPatch_DrawOp, flags, 0);
-        
+
         fWriter.write(cubics, SkPatchUtils::kNumCtrlPts * sizeof(SkPoint));
-        
+
         if (colors) {
             fWriter.write(colors, SkPatchUtils::kNumCorners * sizeof(SkColor));
         }
-        
+
         if (texCoords) {
             fWriter.write(texCoords, SkPatchUtils::kNumCorners * sizeof(SkPoint));
         }
-        
+
         if (flags & kDrawVertices_HasXfermode_DrawOpFlag) {
             SkXfermode::Mode mode = SkXfermode::kModulate_Mode;
             SkAssertResult(xmode->asMode(&mode));
diff --git a/src/utils/SkDeferredCanvas.cpp b/src/utils/SkDeferredCanvas.cpp
index 06f7bb0..826865f 100644
--- a/src/utils/SkDeferredCanvas.cpp
+++ b/src/utils/SkDeferredCanvas.cpp
@@ -866,6 +866,35 @@
     this->recordedDrawCommand();
 }
 
+void SkDeferredCanvas::drawImage(const SkImage* image, SkScalar left, SkScalar top,
+                                 const SkPaint* paint) {
+    SkRect imageRect = SkRect::MakeXYWH(left, top,
+        SkIntToScalar(image->width()), SkIntToScalar(image->height()));
+    if (fDeferredDrawing &&
+        this->isFullFrame(&imageRect, paint) &&
+        (image->isOpaque() || isPaintOpaque(paint, 0))) {
+        this->getDeferredDevice()->skipPendingCommands();
+    }
+
+    AutoImmediateDrawIfNeeded autoDraw(*this, paint);
+    this->drawingCanvas()->drawImage(image, left, top, paint);
+    this->recordedDrawCommand();
+}
+
+void SkDeferredCanvas::drawImageRect(const SkImage* image, const SkRect* src,
+                                     const SkRect& dst,
+                                     const SkPaint* paint) {
+    if (fDeferredDrawing &&
+        this->isFullFrame(&dst, paint) &&
+        (image->isOpaque() || isPaintOpaque(paint, 0))) {
+        this->getDeferredDevice()->skipPendingCommands();
+    }
+
+    AutoImmediateDrawIfNeeded autoDraw(*this, paint);
+    this->drawingCanvas()->drawImageRect(image, src, dst, paint);
+    this->recordedDrawCommand();
+}
+
 void SkDeferredCanvas::drawSprite(const SkBitmap& bitmap, int left, int top,
                                   const SkPaint* paint) {
     SkRect bitmapRect = SkRect::MakeXYWH(