Fixed bug in SkSurface_Gpu to make the surface receive the new copy when copy
on write happens.
Review URL: https://codereview.chromium.org/13195002

git-svn-id: http://skia.googlecode.com/svn/trunk@8622 2bbb7eff-a529-9590-31e7-b0007b416f81
diff --git a/src/image/SkImagePriv.h b/src/image/SkImagePriv.h
index 3210cae..fc14f67 100644
--- a/src/image/SkImagePriv.h
+++ b/src/image/SkImagePriv.h
@@ -55,10 +55,13 @@
 // in which case the surface may need to perform a copy-on-write.
 extern SkPixelRef* SkBitmapImageGetPixelRef(SkImage* rasterImage);
 
+// Given an image created with NewPicture, return its SkPicture.
+extern SkPicture* SkPictureImageGetPicture(SkImage* pictureImage);
+
 // Given an image created with NewTexture, return its GrTexture. This
 // may be called to see if the surface and the image share the same GrTexture,
 // in which case the surface may need to perform a copy-on-write.
-extern GrTexture* SkTextureImageGetTexture(SkImage* rasterImage);
+extern GrTexture* SkTextureImageGetTexture(SkImage* textureImage);
 
 // Update the texture wrapped by an image created with NewTexture. This
 // is called when a surface and image share the same GrTexture and the
diff --git a/src/image/SkImage_Picture.cpp b/src/image/SkImage_Picture.cpp
index 447299f..be934fa 100644
--- a/src/image/SkImage_Picture.cpp
+++ b/src/image/SkImage_Picture.cpp
@@ -16,6 +16,8 @@
 
     virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE;
 
+    SkPicture* getPicture() { return fPicture; }
+
 private:
     SkPicture*  fPicture;
 
@@ -52,3 +54,7 @@
 
     return SkNEW_ARGS(SkImage_Picture, (playback));
 }
+
+SkPicture* SkPictureImageGetPicture(SkImage* pictureImage) {
+    return static_cast<SkImage_Picture*>(pictureImage)->getPicture();
+}
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index 1ed68e5..3c581c3 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -83,31 +83,24 @@
     canvas->drawBitmap(fDevice->accessBitmap(false), x, y, paint);
 }
 
-// Copy the contents of the SkGpuDevice into a new texture and give that
-// texture to the SkImage. Note that this flushes the SkGpuDevice but
+// Create a new SkGpuDevice and, if necessary, copy the contents of the old
+// device into it. Note that this flushes the SkGpuDevice but
 // doesn't force an OpenGL flush.
-void SkSurface_Gpu::onCopyOnWrite(SkImage* image, SkCanvas*) {
+void SkSurface_Gpu::onCopyOnWrite(SkImage* image, SkCanvas* canvas) {
     GrRenderTarget* rt = (GrRenderTarget*) fDevice->accessRenderTarget();
 
     // are we sharing our render target with the image?
     if (rt->asTexture() == SkTextureImageGetTexture(image)) {
-        GrTextureDesc desc;
-        // copyTexture requires a render target as the destination
-        desc.fFlags = kRenderTarget_GrTextureFlagBit;
-        desc.fWidth = fDevice->width();
-        desc.fHeight = fDevice->height();
-        desc.fConfig = SkBitmapConfig2GrPixelConfig(fDevice->config());
-        desc.fSampleCnt = 0;
-
-        SkAutoTUnref<GrTexture> tex(fDevice->context()->createUncachedTexture(desc, NULL, 0));
-        if (NULL == tex) {
-            SkTextureImageSetTexture(image, NULL);
-            return;
-        }
-
-        fDevice->context()->copyTexture(rt->asTexture(), tex->asRenderTarget());
-
-        SkTextureImageSetTexture(image, tex);
+        SkGpuDevice* newDevice = static_cast<SkGpuDevice*>(
+            fDevice->createCompatibleDevice(fDevice->config(), fDevice->width(),
+            fDevice->height(), fDevice->isOpaque()));
+        SkAutoTUnref<SkGpuDevice> aurd(newDevice);
+        fDevice->context()->copyTexture(rt->asTexture(),
+            (GrRenderTarget*)newDevice->accessRenderTarget());
+        SkASSERT(NULL != canvas);
+        SkASSERT(canvas->getDevice() == fDevice);
+        canvas->setDevice(newDevice);
+        SkRefCnt_SafeAssign(fDevice, newDevice);
     }
 }