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 {