add SkImage::newSurface

BUG=skia:

Review URL: https://codereview.chromium.org/741763002
diff --git a/gm/surface.cpp b/gm/surface.cpp
index dbcced2..f84c5ab 100644
--- a/gm/surface.cpp
+++ b/gm/surface.cpp
@@ -105,5 +105,55 @@
 private:
     typedef GM INHERITED;
 };
-
 DEF_GM( return new SurfacePropsGM )
+
+#ifdef SK_DEBUG
+static bool equal(const SkSurfaceProps& a, const SkSurfaceProps& b) {
+    return a.flags() == b.flags() && a.pixelGeometry() == b.pixelGeometry();
+}
+#endif
+
+class NewSurfaceGM : public skiagm::GM {
+public:
+    NewSurfaceGM() {}
+
+protected:
+    SkString onShortName() SK_OVERRIDE {
+        return SkString("surfacenew");
+    }
+
+    virtual SkISize onISize() SK_OVERRIDE {
+        return SkISize::Make(300, 140);
+    }
+
+    static void drawInto(SkCanvas* canvas) {
+        canvas->drawColor(SK_ColorRED);
+    }
+
+    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
+        SkImageInfo info = SkImageInfo::MakeN32Premul(100, 100);
+
+        SkAutoTUnref<SkSurface> surf(canvas->newSurface(info, NULL));
+        if (!surf.get()) {
+            surf.reset(SkSurface::NewRaster(info));
+        }
+        drawInto(surf->getCanvas());
+
+        SkAutoTUnref<SkImage> image(surf->newImageSnapshot());
+        canvas->drawImage(image, 10, 10, NULL);
+
+        SkAutoTUnref<SkSurface> surf2(image->newSurface(info, NULL));
+        drawInto(surf2->getCanvas());
+
+        // Assert that the props were communicated transitively through the first image
+        SkASSERT(equal(surf->props(), surf2->props()));
+
+        SkAutoTUnref<SkImage> image2(surf2->newImageSnapshot());
+        canvas->drawImage(image2, 10 + SkIntToScalar(image->width()) + 10, 10, NULL);
+    }
+
+private:
+    typedef GM INHERITED;
+};
+DEF_GM( return new NewSurfaceGM )
+
diff --git a/include/core/SkImage.h b/include/core/SkImage.h
index 4e01634..63fa41b 100644
--- a/include/core/SkImage.h
+++ b/include/core/SkImage.h
@@ -18,6 +18,8 @@
 class SkCanvas;
 class SkImageGenerator;
 class SkPaint;
+class SkSurface;
+class SkSurfaceProps;
 class GrContext;
 class GrTexture;
 
@@ -92,6 +94,15 @@
     SkData* encode(SkImageEncoder::Type t = SkImageEncoder::kPNG_Type,
                    int quality = 80) const;
 
+    /**
+     *  Return a new surface that is compatible with this image's internal representation
+     *  (e.g. raster or gpu).
+     *
+     *  If no surfaceprops are specified, the image will attempt to match the props of when it
+     *  was created (if it came from a surface).
+     */
+    SkSurface* newSurface(const SkImageInfo&, const SkSurfaceProps* = NULL) const;
+
 protected:
     SkImage(int width, int height) :
         fWidth(width),
diff --git a/include/core/SkSurfaceProps.h b/include/core/SkSurfaceProps.h
index 69a0e52..1083599 100644
--- a/include/core/SkSurfaceProps.h
+++ b/include/core/SkSurfaceProps.h
@@ -62,6 +62,7 @@
     };
     SkSurfaceProps(InitType);
     SkSurfaceProps(uint32_t flags, InitType);
+    SkSurfaceProps(const SkSurfaceProps& other);
 
     uint32_t flags() const { return fFlags; }
     SkPixelGeometry pixelGeometry() const { return fPixelGeometry; }
diff --git a/src/image/SkImage.cpp b/src/image/SkImage.cpp
index f11900d..cbde961 100644
--- a/src/image/SkImage.cpp
+++ b/src/image/SkImage.cpp
@@ -9,14 +9,7 @@
 #include "SkCanvas.h"
 #include "SkImagePriv.h"
 #include "SkImage_Base.h"
-
-static SkImage_Base* as_IB(SkImage* image) {
-    return static_cast<SkImage_Base*>(image);
-}
-
-static const SkImage_Base* as_IB(const SkImage* image) {
-    return static_cast<const SkImage_Base*>(image);
-}
+#include "SkSurface.h"
 
 uint32_t SkImage::NextUniqueID() {
     static int32_t gUniqueID;
@@ -91,6 +84,13 @@
     return NULL;
 }
 
+SkSurface* SkImage::newSurface(const SkImageInfo& info, const SkSurfaceProps* props) const {
+    if (NULL == props) {
+        props = &as_IB(this)->props();
+    }
+    return as_IB(this)->onNewSurface(info, *props);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 static bool raster_canvas_supports(const SkImageInfo& info) {
diff --git a/src/image/SkImagePriv.cpp b/src/image/SkImagePriv.cpp
index bde47e7..ad7b154 100644
--- a/src/image/SkImagePriv.cpp
+++ b/src/image/SkImagePriv.cpp
@@ -6,10 +6,12 @@
  */
 
 #include "SkImagePriv.h"
+#include "SkImage_Base.h"
 #include "SkCanvas.h"
 #include "SkPicture.h"
 
-SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef) {
+SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef,
+                              const SkSurfaceProps* props) {
     const SkImageInfo info = bm.info();
     if (kUnknown_SkColorType == info.colorType()) {
         return NULL;
@@ -17,13 +19,18 @@
 
     SkImage* image = NULL;
     if (canSharePixelRef || bm.isImmutable()) {
-        image = SkNewImageFromPixelRef(info, bm.pixelRef(), bm.rowBytes());
+        image = SkNewImageFromPixelRef(info, bm.pixelRef(), bm.rowBytes(), props);
     } else {
         bm.lockPixels();
         if (bm.getPixels()) {
             image = SkImage::NewRasterCopy(info, bm.getPixels(), bm.rowBytes());
         }
         bm.unlockPixels();
+
+        // we don't expose props to NewRasterCopy (need a private vers) so post-init it here
+        if (image && props) {
+            as_IB(image)->initWithProps(*props);
+        }
     }
     return image;
 }
diff --git a/src/image/SkImagePriv.h b/src/image/SkImagePriv.h
index e9d1d83..db3a089 100644
--- a/src/image/SkImagePriv.h
+++ b/src/image/SkImagePriv.h
@@ -11,8 +11,8 @@
 #include "SkImage.h"
 
 // Call this if you explicitly want to use/share this pixelRef in the image
-extern SkImage* SkNewImageFromPixelRef(const SkImageInfo&, SkPixelRef*,
-                                       size_t rowBytes);
+extern SkImage* SkNewImageFromPixelRef(const SkImageInfo&, SkPixelRef*, size_t rowBytes,
+                                       const SkSurfaceProps*);
 
 /**
  *  Examines the bitmap to decide if it can share the existing pixelRef, or
@@ -24,7 +24,7 @@
  *  SkImageInfo, or the bitmap's pixels cannot be accessed, this will return
  *  NULL.
  */
-extern SkImage* SkNewImageFromBitmap(const SkBitmap&, bool canSharePixelRef);
+extern SkImage* SkNewImageFromBitmap(const SkBitmap&, bool canSharePixelRef, const SkSurfaceProps*);
 
 static inline size_t SkImageMinRowBytes(const SkImageInfo& info) {
     return SkAlign4(info.minRowBytes());
@@ -45,4 +45,6 @@
 // surface needs to perform a copy-on-write
 extern void SkTextureImageSetTexture(SkImage* image, GrTexture* texture);
 
+extern SkImage* SkNewImageFromBitmapTexture(const SkBitmap&, int sampleCount);
+
 #endif
diff --git a/src/image/SkImage_Base.h b/src/image/SkImage_Base.h
index 4ff6a25..8f0fefe 100644
--- a/src/image/SkImage_Base.h
+++ b/src/image/SkImage_Base.h
@@ -9,14 +9,37 @@
 #define SkImage_Base_DEFINED
 
 #include "SkImage.h"
+#include "SkSurface.h"
+
+static SkSurfaceProps copy_or_safe_defaults(const SkSurfaceProps* props) {
+    return props ? *props : SkSurfaceProps(0, kUnknown_SkPixelGeometry);
+}
 
 class SkImage_Base : public SkImage {
 public:
-    SkImage_Base(int width, int height) : INHERITED(width, height) {}
+    SkImage_Base(int width, int height, const SkSurfaceProps* props)
+        : INHERITED(width, height)
+        , fProps(copy_or_safe_defaults(props))
+    {}
+
+    /**
+     *  If the props weren't know at constructor time, call this but only before the image is
+     *  ever released into the wild (since the props field must appear to be immutable).
+     */
+    void initWithProps(const SkSurfaceProps& props) {
+        SkASSERT(this->unique());   // only viewed by one thread
+        SkSurfaceProps* mutableProps = const_cast<SkSurfaceProps*>(&fProps);
+        SkASSERT(mutableProps != &props);   // check for self-assignment
+        mutableProps->~SkSurfaceProps();
+        new (mutableProps) SkSurfaceProps(props);
+    }
+
+    const SkSurfaceProps& props() const { return fProps; }
 
     virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const = 0;
     virtual void onDrawRect(SkCanvas*, const SkRect* src,
                                   const SkRect& dst, const SkPaint*) const = 0;
+    virtual SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const = 0;
 
     // Default impl calls onDraw
     virtual bool onReadPixels(SkBitmap*, const SkIRect& subset) const;
@@ -34,8 +57,19 @@
     virtual SkShader* onNewShader(SkShader::TileMode,
                                   SkShader::TileMode,
                                   const SkMatrix* localMatrix) const { return NULL; };
+
 private:
+    const SkSurfaceProps fProps;
+
     typedef SkImage INHERITED;
 };
 
+static inline SkImage_Base* as_IB(SkImage* image) {
+    return static_cast<SkImage_Base*>(image);
+}
+
+static inline const SkImage_Base* as_IB(const SkImage* image) {
+    return static_cast<const SkImage_Base*>(image);
+}
+
 #endif
diff --git a/src/image/SkImage_Gpu.cpp b/src/image/SkImage_Gpu.cpp
index de49d1e..7a8da36 100644
--- a/src/image/SkImage_Gpu.cpp
+++ b/src/image/SkImage_Gpu.cpp
@@ -9,6 +9,7 @@
 #include "SkImagePriv.h"
 #include "SkBitmap.h"
 #include "SkCanvas.h"
+#include "SkSurface.h"
 #include "GrContext.h"
 #include "GrTexture.h"
 
@@ -16,40 +17,40 @@
 public:
     SK_DECLARE_INST_COUNT(SkImage_Gpu)
 
-    explicit SkImage_Gpu(const SkBitmap&);
-    virtual ~SkImage_Gpu();
+    SkImage_Gpu(const SkBitmap&, int sampleCount);
 
-    virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const SK_OVERRIDE;
-    virtual void onDrawRect(SkCanvas*, const SkRect* src, const SkRect& dst,
-                                  const SkPaint*) const SK_OVERRIDE;
-    virtual GrTexture* onGetTexture() const SK_OVERRIDE;
-    virtual bool getROPixels(SkBitmap*) const SK_OVERRIDE;
+    void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) const SK_OVERRIDE;
+    void onDrawRect(SkCanvas*, const SkRect* src, const SkRect& dst,
+                    const SkPaint*) const SK_OVERRIDE;
+    SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const SK_OVERRIDE;
+    GrTexture* onGetTexture() const SK_OVERRIDE;
+    bool getROPixels(SkBitmap*) const SK_OVERRIDE;
 
     GrTexture* getTexture() const { return fBitmap.getTexture(); }
 
-    virtual SkShader* onNewShader(SkShader::TileMode,
+    SkShader* onNewShader(SkShader::TileMode,
                                   SkShader::TileMode,
                                   const SkMatrix* localMatrix) const SK_OVERRIDE;
 
-    virtual bool isOpaque() const SK_OVERRIDE;
+    bool isOpaque() const SK_OVERRIDE;
 
 private:
     SkBitmap    fBitmap;
+    const int   fSampleCount;   // 0 if we weren't built from a surface
 
     typedef SkImage_Base INHERITED;
 };
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkImage_Gpu::SkImage_Gpu(const SkBitmap& bitmap)
-    : INHERITED(bitmap.width(), bitmap.height())
-    , fBitmap(bitmap) {
+SkImage_Gpu::SkImage_Gpu(const SkBitmap& bitmap, int sampleCount)
+    : INHERITED(bitmap.width(), bitmap.height(), NULL)
+    , fBitmap(bitmap)
+    , fSampleCount(sampleCount)
+{
     SkASSERT(fBitmap.getTexture());
 }
 
-SkImage_Gpu::~SkImage_Gpu() {
-}
-
 SkShader* SkImage_Gpu::onNewShader(SkShader::TileMode tileX,
                                    SkShader::TileMode tileY,
                                    const SkMatrix* localMatrix) const
@@ -66,6 +67,11 @@
     canvas->drawBitmapRectToRect(fBitmap, src, dst, paint);
 }
 
+SkSurface* SkImage_Gpu::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) const {
+    GrContext* ctx = this->getTexture()->getContext();
+    return SkSurface::NewRenderTarget(ctx, info, fSampleCount, &props);
+}
+
 GrTexture* SkImage_Gpu::onGetTexture() const {
     return fBitmap.getTexture();
 }
@@ -80,14 +86,18 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-SkImage* SkImage::NewTexture(const SkBitmap& bitmap) {
+SkImage* SkNewImageFromBitmapTexture(const SkBitmap& bitmap, int sampleCount) {
     if (NULL == bitmap.getTexture()) {
         return NULL;
     }
+    return SkNEW_ARGS(SkImage_Gpu, (bitmap, sampleCount));
+}
 
-    return SkNEW_ARGS(SkImage_Gpu, (bitmap));
+SkImage* SkImage::NewTexture(const SkBitmap& bitmap) {
+    return SkNewImageFromBitmapTexture(bitmap, 0);
 }
 
 GrTexture* SkTextureImageGetTexture(SkImage* image) {
     return ((SkImage_Gpu*)image)->getTexture();
 }
+
diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp
index 18d6a8c..9ae3d36 100644
--- a/src/image/SkImage_Raster.cpp
+++ b/src/image/SkImage_Raster.cpp
@@ -11,6 +11,7 @@
 #include "SkCanvas.h"
 #include "SkData.h"
 #include "SkDecodingImageGenerator.h"
+#include "SkSurface.h"
 
 class SkImage_Raster : public SkImage_Base {
 public:
@@ -50,18 +51,18 @@
 
     static SkImage* NewEmpty();
 
-    SkImage_Raster(const SkImageInfo&, SkData*, size_t rb);
+    SkImage_Raster(const SkImageInfo&, SkData*, size_t rb, const SkSurfaceProps*);
     virtual ~SkImage_Raster();
 
-    virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) const SK_OVERRIDE;
-    virtual void onDrawRect(SkCanvas*, const SkRect*, const SkRect&,
-                                  const SkPaint*) const SK_OVERRIDE;
-    virtual bool onReadPixels(SkBitmap*, const SkIRect&) const SK_OVERRIDE;
-    virtual const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const SK_OVERRIDE;
-    virtual bool getROPixels(SkBitmap*) const SK_OVERRIDE;
+    void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) const SK_OVERRIDE;
+    void onDrawRect(SkCanvas*, const SkRect*, const SkRect&, const SkPaint*) const SK_OVERRIDE;
+    SkSurface* onNewSurface(const SkImageInfo&, const SkSurfaceProps&) const SK_OVERRIDE;
+    bool onReadPixels(SkBitmap*, const SkIRect&) const SK_OVERRIDE;
+    const void* onPeekPixels(SkImageInfo*, size_t* /*rowBytes*/) const SK_OVERRIDE;
+    bool getROPixels(SkBitmap*) const SK_OVERRIDE;
 
     // exposed for SkSurface_Raster via SkNewImageFromPixelRef
-    SkImage_Raster(const SkImageInfo&, SkPixelRef*, size_t rowBytes);
+    SkImage_Raster(const SkImageInfo&, SkPixelRef*, size_t rowBytes, const SkSurfaceProps*);
 
     SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
 
@@ -71,12 +72,12 @@
 
     virtual bool isOpaque() const SK_OVERRIDE;
 
-    SkImage_Raster(const SkBitmap& bm)
-        : INHERITED(bm.width(), bm.height())
+    SkImage_Raster(const SkBitmap& bm, const SkSurfaceProps* props)
+        : INHERITED(bm.width(), bm.height(), props)
         , fBitmap(bm) {}
 
 private:
-    SkImage_Raster() : INHERITED(0, 0) {}
+    SkImage_Raster() : INHERITED(0, 0, NULL) {}
 
     SkBitmap    fBitmap;
 
@@ -100,8 +101,9 @@
     data->unref();
 }
 
-SkImage_Raster::SkImage_Raster(const Info& info, SkData* data, size_t rowBytes)
-    : INHERITED(info.width(), info.height())
+SkImage_Raster::SkImage_Raster(const Info& info, SkData* data, size_t rowBytes,
+                               const SkSurfaceProps* props)
+    : INHERITED(info.width(), info.height(), props)
 {
     data->ref();
     void* addr = const_cast<void*>(data->data());
@@ -112,8 +114,9 @@
     fBitmap.lockPixels();
 }
 
-SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, size_t rowBytes)
-    : INHERITED(info.width(), info.height())
+SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, size_t rowBytes,
+                               const SkSurfaceProps* props)
+    : INHERITED(info.width(), info.height(), props)
 {
     fBitmap.setInfo(info, rowBytes);
     fBitmap.setPixelRef(pr);
@@ -136,6 +139,10 @@
     canvas->drawBitmapRectToRect(fBitmap, src, dst, paint);
 }
 
+SkSurface* SkImage_Raster::onNewSurface(const SkImageInfo& info, const SkSurfaceProps& props) const {
+    return SkSurface::NewRaster(info, &props);
+}
+
 bool SkImage_Raster::onReadPixels(SkBitmap* dst, const SkIRect& subset) const {
     if (dst->pixelRef()) {
         return this->INHERITED::onReadPixels(dst, subset);
@@ -179,7 +186,7 @@
 
     // Here we actually make a copy of the caller's pixel data
     SkAutoDataUnref data(SkData::NewWithCopy(pixels, info.height() * rowBytes));
-    return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes));
+    return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes, NULL));
 }
 
 
@@ -201,7 +208,7 @@
         return NULL;
     }
 
-    return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes));
+    return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes, NULL));
 }
 
 SkImage* SkImage::NewFromGenerator(SkImageGenerator* generator) {
@@ -209,12 +216,12 @@
     if (!SkInstallDiscardablePixelRef(generator, &bitmap)) {
         return NULL;
     }
-    return SkNEW_ARGS(SkImage_Raster, (bitmap));
+    return SkNEW_ARGS(SkImage_Raster, (bitmap, NULL));
 }
 
-SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr,
-                                size_t rowBytes) {
-    return SkNEW_ARGS(SkImage_Raster, (info, pr, rowBytes));
+SkImage* SkNewImageFromPixelRef(const SkImageInfo& info, SkPixelRef* pr, size_t rowBytes,
+                                const SkSurfaceProps* props) {
+    return SkNEW_ARGS(SkImage_Raster, (info, pr, rowBytes, props));
 }
 
 const SkPixelRef* SkBitmapImageGetPixelRef(const SkImage* image) {
diff --git a/src/image/SkSurface.cpp b/src/image/SkSurface.cpp
index b10782a..3ca5747 100644
--- a/src/image/SkSurface.cpp
+++ b/src/image/SkSurface.cpp
@@ -47,6 +47,11 @@
     : fFlags(flags), fPixelGeometry(pg)
 {}
 
+SkSurfaceProps::SkSurfaceProps(const SkSurfaceProps& other)
+    : fFlags(other.fFlags)
+    , fPixelGeometry(other.fPixelGeometry)
+{}
+
 ///////////////////////////////////////////////////////////////////////////////
 
 SkSurface_Base::SkSurface_Base(int width, int height, const SkSurfaceProps* props)
diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp
index d777e3a..9ac6d55 100644
--- a/src/image/SkSurface_Gpu.cpp
+++ b/src/image/SkSurface_Gpu.cpp
@@ -7,6 +7,7 @@
 
 #include "SkSurface_Base.h"
 #include "SkImagePriv.h"
+#include "SkImage_Base.h"
 #include "SkCanvas.h"
 #include "SkGpuDevice.h"
 
@@ -66,7 +67,12 @@
 }
 
 SkImage* SkSurface_Gpu::onNewImageSnapshot() {
-    return SkImage::NewTexture(fDevice->accessBitmap(false));
+    const int sampleCount = fDevice->accessRenderTarget()->numSamples();
+    SkImage* image = SkNewImageFromBitmapTexture(fDevice->accessBitmap(false), sampleCount);
+    if (image) {
+        as_IB(image)->initWithProps(this->props());
+    }
+    return image;
 }
 
 void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
diff --git a/src/image/SkSurface_Raster.cpp b/src/image/SkSurface_Raster.cpp
index cd4f049..b221c13 100644
--- a/src/image/SkSurface_Raster.cpp
+++ b/src/image/SkSurface_Raster.cpp
@@ -115,7 +115,7 @@
 }
 
 SkImage* SkSurface_Raster::onNewImageSnapshot() {
-    return SkNewImageFromBitmap(fBitmap, fWeOwnThePixels);
+    return SkNewImageFromBitmap(fBitmap, fWeOwnThePixels, &this->props());
 }
 
 void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
diff --git a/tests/DeferredCanvasTest.cpp b/tests/DeferredCanvasTest.cpp
index d234c8c..da2d6b9 100644
--- a/tests/DeferredCanvasTest.cpp
+++ b/tests/DeferredCanvasTest.cpp
@@ -65,7 +65,7 @@
     }
 
     virtual SkImage* onNewImageSnapshot() SK_OVERRIDE {
-        return SkNewImageFromBitmap(fBitmap, true);
+        return SkNewImageFromBitmap(fBitmap, true, &this->props());
     }
 
     virtual void onCopyOnWrite(ContentChangeMode mode) SK_OVERRIDE {