summaryrefslogtreecommitdiff
path: root/image
diff options
context:
space:
mode:
Diffstat (limited to 'image')
-rw-r--r--image/SkDataPixelRef.cpp39
-rw-r--r--image/SkDataPixelRef.h35
-rw-r--r--image/SkImage.cpp54
-rw-r--r--image/SkImagePriv.cpp173
-rw-r--r--image/SkImagePriv.h74
-rw-r--r--image/SkImage_Base.h30
-rw-r--r--image/SkImage_Codec.cpp78
-rw-r--r--image/SkImage_Gpu.cpp78
-rw-r--r--image/SkImage_Picture.cpp66
-rw-r--r--image/SkImage_Raster.cpp171
-rw-r--r--image/SkSurface.cpp111
-rw-r--r--image/SkSurface_Base.h96
-rw-r--r--image/SkSurface_Gpu.cpp138
-rw-r--r--image/SkSurface_Picture.cpp92
-rw-r--r--image/SkSurface_Raster.cpp180
15 files changed, 1415 insertions, 0 deletions
diff --git a/image/SkDataPixelRef.cpp b/image/SkDataPixelRef.cpp
new file mode 100644
index 00000000..980b4f14
--- /dev/null
+++ b/image/SkDataPixelRef.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkDataPixelRef.h"
+#include "SkData.h"
+#include "SkFlattenableBuffers.h"
+
+SkDataPixelRef::SkDataPixelRef(SkData* data) : fData(data) {
+ fData->ref();
+ this->setPreLocked(const_cast<void*>(fData->data()), NULL);
+}
+
+SkDataPixelRef::~SkDataPixelRef() {
+ fData->unref();
+}
+
+void* SkDataPixelRef::onLockPixels(SkColorTable** ct) {
+ *ct = NULL;
+ return const_cast<void*>(fData->data());
+}
+
+void SkDataPixelRef::onUnlockPixels() {
+ // nothing to do
+}
+
+void SkDataPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const {
+ this->INHERITED::flatten(buffer);
+ buffer.writeFlattenable(fData);
+}
+
+SkDataPixelRef::SkDataPixelRef(SkFlattenableReadBuffer& buffer)
+ : INHERITED(buffer, NULL) {
+ fData = (SkData*)buffer.readFlattenable();
+ this->setPreLocked(const_cast<void*>(fData->data()), NULL);
+}
diff --git a/image/SkDataPixelRef.h b/image/SkDataPixelRef.h
new file mode 100644
index 00000000..6b15802b
--- /dev/null
+++ b/image/SkDataPixelRef.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkDataPixelRef_DEFINED
+#define SkDataPixelRef_DEFINED
+
+#include "SkPixelRef.h"
+
+class SkData;
+
+class SkDataPixelRef : public SkPixelRef {
+public:
+ SkDataPixelRef(SkData* data);
+ virtual ~SkDataPixelRef();
+
+ SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDataPixelRef)
+
+protected:
+ virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE;
+ virtual void onUnlockPixels() SK_OVERRIDE;
+
+ SkDataPixelRef(SkFlattenableReadBuffer& buffer);
+ virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
+
+private:
+ SkData* fData;
+
+ typedef SkPixelRef INHERITED;
+};
+
+#endif
diff --git a/image/SkImage.cpp b/image/SkImage.cpp
new file mode 100644
index 00000000..39fd93ac
--- /dev/null
+++ b/image/SkImage.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkImagePriv.h"
+#include "SkImage_Base.h"
+
+SK_DEFINE_INST_COUNT(SkImage)
+
+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);
+}
+
+uint32_t SkImage::NextUniqueID() {
+ static int32_t gUniqueID;
+
+ // never return 0;
+ uint32_t id;
+ do {
+ id = sk_atomic_inc(&gUniqueID) + 1;
+ } while (0 == id);
+ return id;
+}
+
+void SkImage::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ as_IB(this)->onDraw(canvas, x, y, paint);
+}
+
+void SkImage::draw(SkCanvas* canvas, const SkRect* src, const SkRect& dst,
+ const SkPaint* paint) {
+ as_IB(this)->onDrawRectToRect(canvas, src, dst, paint);
+}
+
+GrTexture* SkImage::getTexture() {
+ return as_IB(this)->onGetTexture();
+}
+
+SkData* SkImage::encode(SkImageEncoder::Type type, int quality) const {
+ SkBitmap bm;
+ if (as_IB(this)->getROPixels(&bm)) {
+ return SkImageEncoder::EncodeData(bm, type, quality);
+ }
+ return NULL;
+}
diff --git a/image/SkImagePriv.cpp b/image/SkImagePriv.cpp
new file mode 100644
index 00000000..ca4a12cd
--- /dev/null
+++ b/image/SkImagePriv.cpp
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImagePriv.h"
+#include "SkCanvas.h"
+#include "SkPicture.h"
+
+SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info& info,
+ bool* isOpaque) {
+ switch (info.fColorType) {
+ case SkImage::kAlpha_8_ColorType:
+ switch (info.fAlphaType) {
+ case SkImage::kIgnore_AlphaType:
+ // makes no sense
+ return SkBitmap::kNo_Config;
+
+ case SkImage::kOpaque_AlphaType:
+ *isOpaque = true;
+ return SkBitmap::kA8_Config;
+
+ case SkImage::kPremul_AlphaType:
+ case SkImage::kUnpremul_AlphaType:
+ *isOpaque = false;
+ return SkBitmap::kA8_Config;
+ }
+ break;
+
+ case SkImage::kRGB_565_ColorType:
+ // we ignore fAlpahType, though some would not make sense
+ *isOpaque = true;
+ return SkBitmap::kRGB_565_Config;
+
+ case SkImage::kRGBA_8888_ColorType:
+ case SkImage::kBGRA_8888_ColorType:
+ // not supported yet
+ return SkBitmap::kNo_Config;
+
+ case SkImage::kPMColor_ColorType:
+ switch (info.fAlphaType) {
+ case SkImage::kIgnore_AlphaType:
+ case SkImage::kUnpremul_AlphaType:
+ // not supported yet
+ return SkBitmap::kNo_Config;
+ case SkImage::kOpaque_AlphaType:
+ *isOpaque = true;
+ return SkBitmap::kARGB_8888_Config;
+ case SkImage::kPremul_AlphaType:
+ *isOpaque = false;
+ return SkBitmap::kARGB_8888_Config;
+ }
+ break;
+ }
+ SkASSERT(!"how did we get here");
+ return SkBitmap::kNo_Config;
+}
+
+int SkImageBytesPerPixel(SkImage::ColorType ct) {
+ static const uint8_t gColorTypeBytesPerPixel[] = {
+ 1, // kAlpha_8_ColorType
+ 2, // kRGB_565_ColorType
+ 4, // kRGBA_8888_ColorType
+ 4, // kBGRA_8888_ColorType
+ 4, // kPMColor_ColorType
+ };
+
+ SkASSERT((size_t)ct < SK_ARRAY_COUNT(gColorTypeBytesPerPixel));
+ return gColorTypeBytesPerPixel[ct];
+}
+
+bool SkBitmapToImageInfo(const SkBitmap& bm, SkImage::Info* info) {
+ switch (bm.config()) {
+ case SkBitmap::kA8_Config:
+ info->fColorType = SkImage::kAlpha_8_ColorType;
+ break;
+
+ case SkBitmap::kRGB_565_Config:
+ info->fColorType = SkImage::kRGB_565_ColorType;
+ break;
+
+ case SkBitmap::kARGB_8888_Config:
+ info->fColorType = SkImage::kPMColor_ColorType;
+ break;
+
+ default:
+ return false;
+ }
+
+ info->fWidth = bm.width();
+ info->fHeight = bm.height();
+ info->fAlphaType = bm.isOpaque() ? SkImage::kOpaque_AlphaType :
+ SkImage::kPremul_AlphaType;
+ return true;
+}
+
+SkImage* SkNewImageFromBitmap(const SkBitmap& bm, bool canSharePixelRef) {
+ SkImage::Info info;
+ if (!SkBitmapToImageInfo(bm, &info)) {
+ return NULL;
+ }
+
+ SkImage* image = NULL;
+ if (canSharePixelRef || bm.isImmutable()) {
+ image = SkNewImageFromPixelRef(info, bm.pixelRef(), bm.rowBytes());
+ } else {
+ bm.lockPixels();
+ if (bm.getPixels()) {
+ image = SkImage::NewRasterCopy(info, bm.getPixels(), bm.rowBytes());
+ }
+ bm.unlockPixels();
+ }
+ return image;
+}
+
+static bool needs_layer(const SkPaint& paint) {
+ return 0xFF != paint.getAlpha() ||
+ paint.getColorFilter() ||
+ paint.getImageFilter() ||
+ SkXfermode::IsMode(paint.getXfermode(), SkXfermode::kSrcOver_Mode);
+}
+
+void SkImagePrivDrawPicture(SkCanvas* canvas, SkPicture* picture,
+ SkScalar x, SkScalar y, const SkPaint* paint) {
+ int saveCount = canvas->getSaveCount();
+
+ if (paint && needs_layer(*paint)) {
+ SkRect bounds;
+ bounds.set(x, y,
+ x + SkIntToScalar(picture->width()),
+ y + SkIntToScalar(picture->height()));
+ canvas->saveLayer(&bounds, paint);
+ canvas->translate(x, y);
+ } else if (x || y) {
+ canvas->save();
+ canvas->translate(x, y);
+ }
+
+ canvas->drawPicture(*picture);
+ canvas->restoreToCount(saveCount);
+}
+
+void SkImagePrivDrawPicture(SkCanvas* canvas, SkPicture* picture,
+ const SkRect* src, const SkRect& dst, const SkPaint* paint) {
+ int saveCount = canvas->getSaveCount();
+
+ SkMatrix matrix;
+ SkRect tmpSrc;
+
+ if (NULL != src) {
+ tmpSrc = *src;
+ } else {
+ tmpSrc.set(0, 0,
+ SkIntToScalar(picture->width()),
+ SkIntToScalar(picture->height()));
+ }
+
+ matrix.setRectToRect(tmpSrc, dst, SkMatrix::kFill_ScaleToFit);
+ if (paint && needs_layer(*paint)) {
+ canvas->saveLayer(&dst, paint);
+ } else {
+ canvas->save();
+ }
+ canvas->concat(matrix);
+ if (!paint || !needs_layer(*paint)) {
+ canvas->clipRect(tmpSrc);
+ }
+
+ canvas->drawPicture(*picture);
+ canvas->restoreToCount(saveCount);
+}
diff --git a/image/SkImagePriv.h b/image/SkImagePriv.h
new file mode 100644
index 00000000..2af8bbea
--- /dev/null
+++ b/image/SkImagePriv.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkImagePriv_DEFINED
+#define SkImagePriv_DEFINED
+
+#include "SkBitmap.h"
+#include "SkImage.h"
+
+class SkPicture;
+
+extern SkBitmap::Config SkImageInfoToBitmapConfig(const SkImage::Info&,
+ bool* isOpaque);
+
+extern int SkImageBytesPerPixel(SkImage::ColorType);
+
+extern bool SkBitmapToImageInfo(const SkBitmap&, SkImage::Info*);
+
+// Call this if you explicitly want to use/share this pixelRef in the image
+extern SkImage* SkNewImageFromPixelRef(const SkImage::Info&, SkPixelRef*,
+ size_t rowBytes);
+
+/**
+ * Examines the bitmap to decide if it can share the existing pixelRef, or
+ * if it needs to make a deep-copy of the pixels. The bitmap's pixelref will
+ * be shared if either the bitmap is marked as immutable, or canSharePixelRef
+ * is true.
+ *
+ * If the bitmap's config cannot be converted into a corresponding
+ * SkImage::Info, or the bitmap's pixels cannot be accessed, this will return
+ * NULL.
+ */
+extern SkImage* SkNewImageFromBitmap(const SkBitmap&, bool canSharePixelRef);
+
+extern void SkImagePrivDrawPicture(SkCanvas*, SkPicture*,
+ SkScalar x, SkScalar y, const SkPaint*);
+
+extern void SkImagePrivDrawPicture(SkCanvas*, SkPicture*,
+ const SkRect*, const SkRect&, const SkPaint*);
+
+/**
+ * Return an SkImage whose contents are those of the specified picture. Note:
+ * The picture itself is unmodified, and may continue to be used for recording
+ */
+extern SkImage* SkNewImageFromPicture(const SkPicture*);
+
+static inline size_t SkImageMinRowBytes(const SkImage::Info& info) {
+ size_t rb = info.fWidth * SkImageBytesPerPixel(info.fColorType);
+ return SkAlign4(rb);
+}
+
+// Given an image created from SkNewImageFromBitmap, return its pixelref. This
+// may be called to see if the surface and the image share the same pixelref,
+// 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* 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
+// surface needs to perform a copy-on-write
+extern void SkTextureImageSetTexture(SkImage* image, GrTexture* texture);
+
+#endif
diff --git a/image/SkImage_Base.h b/image/SkImage_Base.h
new file mode 100644
index 00000000..7bd1f7e6
--- /dev/null
+++ b/image/SkImage_Base.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkImage_Base_DEFINED
+#define SkImage_Base_DEFINED
+
+#include "SkImage.h"
+
+class SkImage_Base : public SkImage {
+public:
+ SkImage_Base(int width, int height) : INHERITED(width, height) {}
+
+ virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) = 0;
+ virtual void onDrawRectToRect(SkCanvas*, const SkRect* src,
+ const SkRect& dst, const SkPaint*) = 0;
+ virtual GrTexture* onGetTexture() { return NULL; }
+
+ // return a read-only copy of the pixels. We promise to not modify them,
+ // but only inspect them (or encode them).
+ virtual bool getROPixels(SkBitmap*) const { return false; }
+
+private:
+ typedef SkImage INHERITED;
+};
+
+#endif
diff --git a/image/SkImage_Codec.cpp b/image/SkImage_Codec.cpp
new file mode 100644
index 00000000..64f58a6a
--- /dev/null
+++ b/image/SkImage_Codec.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImageDecoder.h"
+#include "SkImage_Base.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+
+class SkImage_Codec : public SkImage_Base {
+public:
+ static SkImage* NewEmpty();
+
+ SkImage_Codec(SkData* encodedData, int width, int height);
+ virtual ~SkImage_Codec();
+
+ virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE;
+ virtual void onDrawRectToRect(SkCanvas*, const SkRect*, const SkRect&, const SkPaint*) SK_OVERRIDE;
+
+private:
+ SkData* fEncodedData;
+ SkBitmap fBitmap;
+
+ typedef SkImage_Base INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkImage_Codec::SkImage_Codec(SkData* data, int width, int height) : INHERITED(width, height) {
+ fEncodedData = data;
+ fEncodedData->ref();
+}
+
+SkImage_Codec::~SkImage_Codec() {
+ fEncodedData->unref();
+}
+
+void SkImage_Codec::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
+ if (!fBitmap.pixelRef()) {
+ if (!SkImageDecoder::DecodeMemory(fEncodedData->bytes(), fEncodedData->size(),
+ &fBitmap)) {
+ return;
+ }
+ }
+ canvas->drawBitmap(fBitmap, x, y, paint);
+}
+
+void SkImage_Codec::onDrawRectToRect(SkCanvas* canvas, const SkRect* src,
+ const SkRect& dst, const SkPaint* paint) {
+ if (!fBitmap.pixelRef()) {
+ if (!SkImageDecoder::DecodeMemory(fEncodedData->bytes(), fEncodedData->size(),
+ &fBitmap)) {
+ return;
+ }
+ }
+ canvas->drawBitmapRectToRect(fBitmap, src, dst, paint);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkImage* SkImage::NewEncodedData(SkData* data) {
+ if (NULL == data) {
+ return NULL;
+ }
+
+ SkBitmap bitmap;
+ if (!SkImageDecoder::DecodeMemory(data->bytes(), data->size(), &bitmap,
+ SkBitmap::kNo_Config,
+ SkImageDecoder::kDecodeBounds_Mode)) {
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkImage_Codec, (data, bitmap.width(), bitmap.height()));
+}
diff --git a/image/SkImage_Gpu.cpp b/image/SkImage_Gpu.cpp
new file mode 100644
index 00000000..036e45bb
--- /dev/null
+++ b/image/SkImage_Gpu.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImage_Base.h"
+#include "SkImagePriv.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "GrContext.h"
+#include "GrTexture.h"
+#include "SkGrPixelRef.h"
+
+class SkImage_Gpu : public SkImage_Base {
+public:
+ SK_DECLARE_INST_COUNT(SkImage_Gpu)
+
+ explicit SkImage_Gpu(const SkBitmap&);
+ virtual ~SkImage_Gpu();
+
+ virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*) SK_OVERRIDE;
+ virtual void onDrawRectToRect(SkCanvas*, const SkRect* src, const SkRect& dst, const SkPaint*) SK_OVERRIDE;
+ virtual GrTexture* onGetTexture() SK_OVERRIDE;
+ virtual bool getROPixels(SkBitmap*) const SK_OVERRIDE {
+ // TODO
+ return false;
+ }
+
+ GrTexture* getTexture() { return fBitmap.getTexture(); }
+
+private:
+ SkBitmap fBitmap;
+
+ typedef SkImage_Base INHERITED;
+};
+
+SK_DEFINE_INST_COUNT(SkImage_Gpu)
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkImage_Gpu::SkImage_Gpu(const SkBitmap& bitmap)
+ : INHERITED(bitmap.width(), bitmap.height())
+ , fBitmap(bitmap) {
+ SkASSERT(NULL != fBitmap.getTexture());
+}
+
+SkImage_Gpu::~SkImage_Gpu() {
+}
+
+void SkImage_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ canvas->drawBitmap(fBitmap, x, y, paint);
+}
+
+void SkImage_Gpu::onDrawRectToRect(SkCanvas* canvas, const SkRect* src, const SkRect& dst,
+ const SkPaint* paint) {
+ canvas->drawBitmapRectToRect(fBitmap, src, dst, paint);
+}
+
+GrTexture* SkImage_Gpu::onGetTexture() {
+ return fBitmap.getTexture();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkImage* SkImage::NewTexture(const SkBitmap& bitmap) {
+ if (NULL == bitmap.getTexture()) {
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkImage_Gpu, (bitmap));
+}
+
+GrTexture* SkTextureImageGetTexture(SkImage* image) {
+ return ((SkImage_Gpu*)image)->getTexture();
+}
diff --git a/image/SkImage_Picture.cpp b/image/SkImage_Picture.cpp
new file mode 100644
index 00000000..87221de2
--- /dev/null
+++ b/image/SkImage_Picture.cpp
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImage_Base.h"
+#include "SkImagePriv.h"
+#include "SkPicture.h"
+
+class SkImage_Picture : public SkImage_Base {
+public:
+ SkImage_Picture(SkPicture*);
+ virtual ~SkImage_Picture();
+
+ virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE;
+ virtual void onDrawRectToRect(SkCanvas*, const SkRect*, const SkRect&, const SkPaint*) SK_OVERRIDE;
+
+ SkPicture* getPicture() { return fPicture; }
+
+private:
+ SkPicture* fPicture;
+
+ typedef SkImage_Base INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkImage_Picture::SkImage_Picture(SkPicture* pict) : INHERITED(pict->width(), pict->height()) {
+ pict->endRecording();
+ pict->ref();
+ fPicture = pict;
+}
+
+SkImage_Picture::~SkImage_Picture() {
+ fPicture->unref();
+}
+
+void SkImage_Picture::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ SkImagePrivDrawPicture(canvas, fPicture, x, y, paint);
+}
+
+void SkImage_Picture::onDrawRectToRect(SkCanvas* canvas, const SkRect* src, const SkRect& dst,
+ const SkPaint* paint) {
+ SkImagePrivDrawPicture(canvas, fPicture, src, dst, paint);
+}
+
+SkImage* SkNewImageFromPicture(const SkPicture* srcPicture) {
+ /**
+ * We want to snapshot the playback status of the picture, w/o affecting
+ * its ability to continue recording (if needed).
+ *
+ * Optimally this will shared as much data/buffers as it can with
+ * srcPicture, and srcPicture will perform a copy-on-write as needed if it
+ * needs to mutate them later on.
+ */
+ SkAutoTUnref<SkPicture> playback(SkNEW_ARGS(SkPicture, (*srcPicture)));
+
+ return SkNEW_ARGS(SkImage_Picture, (playback));
+}
+
+SkPicture* SkPictureImageGetPicture(SkImage* pictureImage) {
+ return static_cast<SkImage_Picture*>(pictureImage)->getPicture();
+}
diff --git a/image/SkImage_Raster.cpp b/image/SkImage_Raster.cpp
new file mode 100644
index 00000000..3e268560
--- /dev/null
+++ b/image/SkImage_Raster.cpp
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkImage_Base.h"
+#include "SkImagePriv.h"
+#include "SkBitmap.h"
+#include "SkCanvas.h"
+#include "SkData.h"
+#include "SkDataPixelRef.h"
+
+class SkImage_Raster : public SkImage_Base {
+public:
+ static bool ValidArgs(const Info& info, size_t rowBytes) {
+ const int maxDimension = SK_MaxS32 >> 2;
+ const size_t kMaxPixelByteSize = SK_MaxS32;
+
+ if (info.fWidth < 0 || info.fHeight < 0) {
+ return false;
+ }
+ if (info.fWidth > maxDimension || info.fHeight > maxDimension) {
+ return false;
+ }
+ if ((unsigned)info.fColorType > (unsigned)kLastEnum_ColorType) {
+ return false;
+ }
+ if ((unsigned)info.fAlphaType > (unsigned)kLastEnum_AlphaType) {
+ return false;
+ }
+
+ bool isOpaque;
+ if (SkImageInfoToBitmapConfig(info, &isOpaque) == SkBitmap::kNo_Config) {
+ return false;
+ }
+
+ // TODO: check colorspace
+
+ if (rowBytes < SkImageMinRowBytes(info)) {
+ return false;
+ }
+
+ int64_t size = (int64_t)info.fHeight * rowBytes;
+ if (size > (int64_t)kMaxPixelByteSize) {
+ return false;
+ }
+ return true;
+ }
+
+ static SkImage* NewEmpty();
+
+ SkImage_Raster(const SkImage::Info&, SkData*, size_t rb);
+ virtual ~SkImage_Raster();
+
+ virtual void onDraw(SkCanvas*, SkScalar, SkScalar, const SkPaint*) SK_OVERRIDE;
+ virtual void onDrawRectToRect(SkCanvas*, const SkRect*, const SkRect&, const SkPaint*) SK_OVERRIDE;
+ virtual bool getROPixels(SkBitmap*) const SK_OVERRIDE;
+
+ // exposed for SkSurface_Raster via SkNewImageFromPixelRef
+ SkImage_Raster(const SkImage::Info&, SkPixelRef*, size_t rowBytes);
+
+ SkPixelRef* getPixelRef() const { return fBitmap.pixelRef(); }
+
+private:
+ SkImage_Raster() : INHERITED(0, 0) {}
+
+ SkBitmap fBitmap;
+
+ typedef SkImage_Base INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkImage* SkImage_Raster::NewEmpty() {
+ // Returns lazily created singleton
+ static SkImage* gEmpty;
+ if (NULL == gEmpty) {
+ gEmpty = SkNEW(SkImage_Raster);
+ }
+ gEmpty->ref();
+ return gEmpty;
+}
+
+SkImage_Raster::SkImage_Raster(const Info& info, SkData* data, size_t rowBytes)
+ : INHERITED(info.fWidth, info.fHeight) {
+ bool isOpaque;
+ SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+
+ fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
+ fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref();
+ fBitmap.setIsOpaque(isOpaque);
+ fBitmap.setImmutable();
+}
+
+SkImage_Raster::SkImage_Raster(const Info& info, SkPixelRef* pr, size_t rowBytes)
+: INHERITED(info.fWidth, info.fHeight) {
+ bool isOpaque;
+ SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+
+ fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes);
+ fBitmap.setPixelRef(pr);
+ fBitmap.setIsOpaque(isOpaque);
+}
+
+SkImage_Raster::~SkImage_Raster() {}
+
+void SkImage_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, const SkPaint* paint) {
+ canvas->drawBitmap(fBitmap, x, y, paint);
+}
+
+void SkImage_Raster::onDrawRectToRect(SkCanvas* canvas, const SkRect* src, const SkRect& dst, const SkPaint* paint) {
+ canvas->drawBitmapRectToRect(fBitmap, src, dst, paint);
+}
+
+bool SkImage_Raster::getROPixels(SkBitmap* dst) const {
+ *dst = fBitmap;
+ return true;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkImage* SkImage::NewRasterCopy(const SkImage::Info& info, const void* pixels, size_t rowBytes) {
+ if (!SkImage_Raster::ValidArgs(info, rowBytes)) {
+ return NULL;
+ }
+ if (0 == info.fWidth && 0 == info.fHeight) {
+ return SkImage_Raster::NewEmpty();
+ }
+ // check this after empty-check
+ if (NULL == pixels) {
+ return NULL;
+ }
+
+ // Here we actually make a copy of the caller's pixel data
+ SkAutoDataUnref data(SkData::NewWithCopy(pixels, info.fHeight * rowBytes));
+ return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes));
+}
+
+
+SkImage* SkImage::NewRasterData(const SkImage::Info& info, SkData* pixelData, size_t rowBytes) {
+ if (!SkImage_Raster::ValidArgs(info, rowBytes)) {
+ return NULL;
+ }
+ if (0 == info.fWidth && 0 == info.fHeight) {
+ return SkImage_Raster::NewEmpty();
+ }
+ // check this after empty-check
+ if (NULL == pixelData) {
+ return NULL;
+ }
+
+ // did they give us enough data?
+ size_t size = info.fHeight * rowBytes;
+ if (pixelData->size() < size) {
+ return NULL;
+ }
+
+ SkAutoDataUnref data(pixelData);
+ return SkNEW_ARGS(SkImage_Raster, (info, data, rowBytes));
+}
+
+SkImage* SkNewImageFromPixelRef(const SkImage::Info& info, SkPixelRef* pr,
+ size_t rowBytes) {
+ return SkNEW_ARGS(SkImage_Raster, (info, pr, rowBytes));
+}
+
+SkPixelRef* SkBitmapImageGetPixelRef(SkImage* image) {
+ return ((SkImage_Raster*)image)->getPixelRef();
+}
diff --git a/image/SkSurface.cpp b/image/SkSurface.cpp
new file mode 100644
index 00000000..1dff7ec7
--- /dev/null
+++ b/image/SkSurface.cpp
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSurface_Base.h"
+#include "SkImagePriv.h"
+#include "SkCanvas.h"
+
+SK_DEFINE_INST_COUNT(SkSurface)
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkSurface_Base::SkSurface_Base(int width, int height) : INHERITED(width, height) {
+ fCachedCanvas = NULL;
+ fCachedImage = NULL;
+}
+
+SkSurface_Base::~SkSurface_Base() {
+ // in case the canvas outsurvives us, we null the callback
+ if (fCachedCanvas) {
+ fCachedCanvas->setSurfaceBase(NULL);
+ }
+
+ SkSafeUnref(fCachedImage);
+ SkSafeUnref(fCachedCanvas);
+}
+
+void SkSurface_Base::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ SkImage* image = this->newImageSnapshot();
+ if (image) {
+ image->draw(canvas, x, y, paint);
+ image->unref();
+ }
+}
+
+void SkSurface_Base::aboutToDraw(ContentChangeMode mode) {
+ this->dirtyGenerationID();
+
+ if (NULL != fCachedCanvas) {
+ SkASSERT(fCachedCanvas->getSurfaceBase() == this || \
+ NULL == fCachedCanvas->getSurfaceBase());
+ fCachedCanvas->setSurfaceBase(NULL);
+ }
+
+ if (NULL != fCachedImage) {
+ // the surface may need to fork its backend, if its sharing it with
+ // the cached image. Note: we only call if there is an outstanding owner
+ // on the image (besides us).
+ if (!fCachedImage->unique()) {
+ this->onCopyOnWrite(mode);
+ }
+
+ // regardless of copy-on-write, we must drop our cached image now, so
+ // that the next request will get our new contents.
+ fCachedImage->unref();
+ fCachedImage = NULL;
+ }
+}
+
+uint32_t SkSurface_Base::newGenerationID() {
+ this->installIntoCanvasForDirtyNotification();
+
+ static int32_t gID;
+ return sk_atomic_inc(&gID) + 1;
+}
+
+static SkSurface_Base* asSB(SkSurface* surface) {
+ return static_cast<SkSurface_Base*>(surface);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkSurface::SkSurface(int width, int height) : fWidth(width), fHeight(height) {
+ SkASSERT(width >= 0);
+ SkASSERT(height >= 0);
+ fGenerationID = 0;
+}
+
+uint32_t SkSurface::generationID() {
+ if (0 == fGenerationID) {
+ fGenerationID = asSB(this)->newGenerationID();
+ }
+ return fGenerationID;
+}
+
+void SkSurface::notifyContentWillChange(ContentChangeMode mode) {
+ asSB(this)->aboutToDraw(mode);
+}
+
+SkCanvas* SkSurface::getCanvas() {
+ return asSB(this)->getCachedCanvas();
+}
+
+SkImage* SkSurface::newImageSnapshot() {
+ SkImage* image = asSB(this)->getCachedImage();
+ SkSafeRef(image); // the caller will call unref() to balance this
+ return image;
+}
+
+SkSurface* SkSurface::newSurface(const SkImage::Info& info) {
+ return asSB(this)->onNewSurface(info);
+}
+
+void SkSurface::draw(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ return asSB(this)->onDraw(canvas, x, y, paint);
+}
diff --git a/image/SkSurface_Base.h b/image/SkSurface_Base.h
new file mode 100644
index 00000000..6ea8d60b
--- /dev/null
+++ b/image/SkSurface_Base.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef SkSurface_Base_DEFINED
+#define SkSurface_Base_DEFINED
+
+#include "SkSurface.h"
+#include "SkCanvas.h"
+
+class SkSurface_Base : public SkSurface {
+public:
+ SkSurface_Base(int width, int height);
+ virtual ~SkSurface_Base();
+
+ /**
+ * Allocate a canvas that will draw into this surface. We will cache this
+ * canvas, to return the same object to the caller multiple times. We
+ * take ownership, and will call unref() on the canvas when we go out of
+ * scope.
+ */
+ virtual SkCanvas* onNewCanvas() = 0;
+
+ virtual SkSurface* onNewSurface(const SkImage::Info&) = 0;
+
+ /**
+ * Allocate an SkImage that represents the current contents of the surface.
+ * This needs to be able to outlive the surface itself (if need be), and
+ * must faithfully represent the current contents, even if the surface
+ * is chaged after this calle (e.g. it is drawn to via its canvas).
+ */
+ virtual SkImage* onNewImageSnapshot() = 0;
+
+ /**
+ * Default implementation:
+ *
+ * image = this->newImageSnapshot();
+ * if (image) {
+ * image->draw(canvas, ...);
+ * image->unref();
+ * }
+ */
+ virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, const SkPaint*);
+
+ /**
+ * If the surface is about to change, we call this so that our subclass
+ * can optionally fork their backend (copy-on-write) in case it was
+ * being shared with the cachedImage.
+ */
+ virtual void onCopyOnWrite(ContentChangeMode) = 0;
+
+ inline SkCanvas* getCachedCanvas();
+ inline SkImage* getCachedImage();
+
+ // called by SkSurface to compute a new genID
+ uint32_t newGenerationID();
+
+private:
+ SkCanvas* fCachedCanvas;
+ SkImage* fCachedImage;
+
+ void aboutToDraw(ContentChangeMode mode);
+ friend class SkCanvas;
+ friend class SkSurface;
+
+ inline void installIntoCanvasForDirtyNotification();
+
+ typedef SkSurface INHERITED;
+};
+
+SkCanvas* SkSurface_Base::getCachedCanvas() {
+ if (NULL == fCachedCanvas) {
+ fCachedCanvas = this->onNewCanvas();
+ this->installIntoCanvasForDirtyNotification();
+ }
+ return fCachedCanvas;
+}
+
+SkImage* SkSurface_Base::getCachedImage() {
+ if (NULL == fCachedImage) {
+ fCachedImage = this->onNewImageSnapshot();
+ this->installIntoCanvasForDirtyNotification();
+ }
+ return fCachedImage;
+}
+
+void SkSurface_Base::installIntoCanvasForDirtyNotification() {
+ if (NULL != fCachedCanvas) {
+ fCachedCanvas->setSurfaceBase(this);
+ }
+}
+
+#endif
diff --git a/image/SkSurface_Gpu.cpp b/image/SkSurface_Gpu.cpp
new file mode 100644
index 00000000..e5b7bd44
--- /dev/null
+++ b/image/SkSurface_Gpu.cpp
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSurface_Base.h"
+#include "SkImagePriv.h"
+#include "SkCanvas.h"
+#include "SkGpuDevice.h"
+
+class SkSurface_Gpu : public SkSurface_Base {
+public:
+ SK_DECLARE_INST_COUNT(SkSurface_Gpu)
+
+ SkSurface_Gpu(GrContext*, const SkImage::Info&, int sampleCount);
+ SkSurface_Gpu(GrContext*, GrRenderTarget*);
+ virtual ~SkSurface_Gpu();
+
+ virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
+ virtual SkSurface* onNewSurface(const SkImage::Info&) SK_OVERRIDE;
+ virtual SkImage* onNewImageSnapshot() SK_OVERRIDE;
+ virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
+ const SkPaint*) SK_OVERRIDE;
+ virtual void onCopyOnWrite(ContentChangeMode) SK_OVERRIDE;
+
+private:
+ SkGpuDevice* fDevice;
+
+ typedef SkSurface_Base INHERITED;
+};
+
+SK_DEFINE_INST_COUNT(SkSurface_Gpu)
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkSurface_Gpu::SkSurface_Gpu(GrContext* ctx, const SkImage::Info& info,
+ int sampleCount)
+ : INHERITED(info.fWidth, info.fHeight) {
+ bool isOpaque;
+ SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+
+ fDevice = SkNEW_ARGS(SkGpuDevice, (ctx, config, info.fWidth, info.fHeight, sampleCount));
+
+ if (!isOpaque) {
+ fDevice->clear(0x0);
+ }
+}
+
+SkSurface_Gpu::SkSurface_Gpu(GrContext* ctx, GrRenderTarget* renderTarget)
+ : INHERITED(renderTarget->width(), renderTarget->height()) {
+ fDevice = SkNEW_ARGS(SkGpuDevice, (ctx, renderTarget));
+
+ if (kRGB_565_GrPixelConfig != renderTarget->config()) {
+ fDevice->clear(0x0);
+ }
+}
+
+SkSurface_Gpu::~SkSurface_Gpu() {
+ SkSafeUnref(fDevice);
+}
+
+SkCanvas* SkSurface_Gpu::onNewCanvas() {
+ return SkNEW_ARGS(SkCanvas, (fDevice));
+}
+
+SkSurface* SkSurface_Gpu::onNewSurface(const SkImage::Info& info) {
+ GrRenderTarget* rt = fDevice->accessRenderTarget();
+ int sampleCount = rt->numSamples();
+ return SkSurface::NewRenderTarget(fDevice->context(), info, sampleCount);
+}
+
+SkImage* SkSurface_Gpu::onNewImageSnapshot() {
+ return SkImage::NewTexture(fDevice->accessBitmap(false));
+}
+
+void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ canvas->drawBitmap(fDevice->accessBitmap(false), x, y, paint);
+}
+
+// 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(ContentChangeMode mode) {
+ GrRenderTarget* rt = fDevice->accessRenderTarget();
+ // are we sharing our render target with the image?
+ SkASSERT(NULL != this->getCachedImage());
+ if (rt->asTexture() == SkTextureImageGetTexture(this->getCachedImage())) {
+ SkGpuDevice* newDevice = static_cast<SkGpuDevice*>(
+ fDevice->createCompatibleDevice(fDevice->config(), fDevice->width(),
+ fDevice->height(), fDevice->isOpaque()));
+ SkAutoTUnref<SkGpuDevice> aurd(newDevice);
+ if (kRetain_ContentChangeMode == mode) {
+ fDevice->context()->copyTexture(rt->asTexture(),
+ reinterpret_cast<GrRenderTarget*>(newDevice->accessRenderTarget()));
+ }
+ SkASSERT(NULL != this->getCachedCanvas());
+ SkASSERT(this->getCachedCanvas()->getDevice() == fDevice);
+ this->getCachedCanvas()->setDevice(newDevice);
+ SkRefCnt_SafeAssign(fDevice, newDevice);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkSurface* SkSurface::NewRenderTargetDirect(GrContext* ctx,
+ GrRenderTarget* target) {
+ if (NULL == ctx || NULL == target) {
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkSurface_Gpu, (ctx, target));
+}
+
+SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImage::Info& info, int sampleCount) {
+ if (NULL == ctx) {
+ return NULL;
+ }
+
+ bool isOpaque;
+ SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+
+ GrTextureDesc desc;
+ desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit;
+ desc.fWidth = info.fWidth;
+ desc.fHeight = info.fHeight;
+ desc.fConfig = SkBitmapConfig2GrPixelConfig(config);
+ desc.fSampleCnt = sampleCount;
+
+ SkAutoTUnref<GrTexture> tex(ctx->createUncachedTexture(desc, NULL, 0));
+ if (NULL == tex) {
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkSurface_Gpu, (ctx, tex->asRenderTarget()));
+}
diff --git a/image/SkSurface_Picture.cpp b/image/SkSurface_Picture.cpp
new file mode 100644
index 00000000..79812c4a
--- /dev/null
+++ b/image/SkSurface_Picture.cpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSurface_Base.h"
+#include "SkCanvas.h"
+#include "SkImagePriv.h"
+#include "SkPicture.h"
+
+/**
+ * What does it mean to ask for more than one canvas from a picture?
+ * How do we return an Image and then "continue" recording?
+ */
+class SkSurface_Picture : public SkSurface_Base {
+public:
+ SkSurface_Picture(int width, int height);
+ virtual ~SkSurface_Picture();
+
+ virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
+ virtual SkSurface* onNewSurface(const SkImage::Info&) SK_OVERRIDE;
+ virtual SkImage* onNewImageSnapshot() SK_OVERRIDE;
+ virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
+ const SkPaint*) SK_OVERRIDE;
+ virtual void onCopyOnWrite(ContentChangeMode) SK_OVERRIDE;
+
+private:
+ SkPicture* fPicture;
+
+ typedef SkSurface_Base INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkSurface_Picture::SkSurface_Picture(int width, int height) : INHERITED(width, height) {
+ fPicture = NULL;
+}
+
+SkSurface_Picture::~SkSurface_Picture() {
+ SkSafeUnref(fPicture);
+}
+
+SkCanvas* SkSurface_Picture::onNewCanvas() {
+ if (!fPicture) {
+ fPicture = SkNEW(SkPicture);
+ }
+ SkCanvas* canvas = fPicture->beginRecording(this->width(), this->height());
+ canvas->ref(); // our caller will call unref()
+ return canvas;
+}
+
+SkSurface* SkSurface_Picture::onNewSurface(const SkImage::Info& info) {
+ return SkSurface::NewPicture(info.fWidth, info.fHeight);
+}
+
+SkImage* SkSurface_Picture::onNewImageSnapshot() {
+ if (fPicture) {
+ return SkNewImageFromPicture(fPicture);
+ } else {
+ SkImage::Info info;
+ info.fWidth = info.fHeight = 0;
+ info.fColorType = SkImage::kPMColor_ColorType;
+ info.fAlphaType = SkImage::kOpaque_AlphaType;
+ return SkImage::NewRasterCopy(info, NULL, 0);
+ }
+}
+
+void SkSurface_Picture::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ if (!fPicture) {
+ return;
+ }
+ SkImagePrivDrawPicture(canvas, fPicture, x, y, paint);
+}
+
+void SkSurface_Picture::onCopyOnWrite(ContentChangeMode /*mode*/) {
+ // We always spawn a copy of the recording picture when we
+ // are asked for a snapshot, so we never need to do anything here.
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+
+SkSurface* SkSurface::NewPicture(int width, int height) {
+ if ((width | height) < 0) {
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkSurface_Picture, (width, height));
+}
diff --git a/image/SkSurface_Raster.cpp b/image/SkSurface_Raster.cpp
new file mode 100644
index 00000000..ccfdd27b
--- /dev/null
+++ b/image/SkSurface_Raster.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2012 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkSurface_Base.h"
+#include "SkImagePriv.h"
+#include "SkCanvas.h"
+#include "SkDevice.h"
+#include "SkMallocPixelRef.h"
+
+static const size_t kIgnoreRowBytesValue = (size_t)~0;
+
+class SkSurface_Raster : public SkSurface_Base {
+public:
+ static bool Valid(const SkImage::Info&, size_t rb = kIgnoreRowBytesValue);
+
+ SkSurface_Raster(const SkImage::Info&, void*, size_t rb);
+ SkSurface_Raster(const SkImage::Info&, SkPixelRef*, size_t rb);
+
+ virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
+ virtual SkSurface* onNewSurface(const SkImage::Info&) SK_OVERRIDE;
+ virtual SkImage* onNewImageSnapshot() SK_OVERRIDE;
+ virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
+ const SkPaint*) SK_OVERRIDE;
+ virtual void onCopyOnWrite(ContentChangeMode) SK_OVERRIDE;
+
+private:
+ SkBitmap fBitmap;
+ bool fWeOwnThePixels;
+
+ typedef SkSurface_Base INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+bool SkSurface_Raster::Valid(const SkImage::Info& info, size_t rowBytes) {
+ static const size_t kMaxTotalSize = SK_MaxS32;
+
+ bool isOpaque;
+ SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+
+ int shift = 0;
+ switch (config) {
+ case SkBitmap::kA8_Config:
+ shift = 0;
+ break;
+ case SkBitmap::kRGB_565_Config:
+ shift = 1;
+ break;
+ case SkBitmap::kARGB_8888_Config:
+ shift = 2;
+ break;
+ default:
+ return false;
+ }
+
+ // TODO: examine colorspace
+
+ if (kIgnoreRowBytesValue == rowBytes) {
+ return true;
+ }
+
+ uint64_t minRB = (uint64_t)info.fWidth << shift;
+ if (minRB > rowBytes) {
+ return false;
+ }
+
+ size_t alignedRowBytes = rowBytes >> shift << shift;
+ if (alignedRowBytes != rowBytes) {
+ return false;
+ }
+
+ uint64_t size = (uint64_t)info.fHeight * rowBytes;
+ if (size > kMaxTotalSize) {
+ return false;
+ }
+
+ return true;
+}
+
+SkSurface_Raster::SkSurface_Raster(const SkImage::Info& info, void* pixels, size_t rb)
+ : INHERITED(info.fWidth, info.fHeight) {
+ bool isOpaque;
+ SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+
+ fBitmap.setConfig(config, info.fWidth, info.fHeight, rb);
+ fBitmap.setPixels(pixels);
+ fBitmap.setIsOpaque(isOpaque);
+ fWeOwnThePixels = false; // We are "Direct"
+}
+
+SkSurface_Raster::SkSurface_Raster(const SkImage::Info& info, SkPixelRef* pr, size_t rb)
+ : INHERITED(info.fWidth, info.fHeight) {
+ bool isOpaque;
+ SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
+
+ fBitmap.setConfig(config, info.fWidth, info.fHeight, rb);
+ fBitmap.setPixelRef(pr);
+ fBitmap.setIsOpaque(isOpaque);
+ fWeOwnThePixels = true;
+
+ if (!isOpaque) {
+ fBitmap.eraseColor(SK_ColorTRANSPARENT);
+ }
+}
+
+SkCanvas* SkSurface_Raster::onNewCanvas() {
+ return SkNEW_ARGS(SkCanvas, (fBitmap));
+}
+
+SkSurface* SkSurface_Raster::onNewSurface(const SkImage::Info& info) {
+ return SkSurface::NewRaster(info);
+}
+
+void SkSurface_Raster::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
+ const SkPaint* paint) {
+ canvas->drawBitmap(fBitmap, x, y, paint);
+}
+
+SkImage* SkSurface_Raster::onNewImageSnapshot() {
+ return SkNewImageFromBitmap(fBitmap, fWeOwnThePixels);
+}
+
+void SkSurface_Raster::onCopyOnWrite(ContentChangeMode mode) {
+ // are we sharing pixelrefs with the image?
+ SkASSERT(NULL != this->getCachedImage());
+ if (SkBitmapImageGetPixelRef(this->getCachedImage()) == fBitmap.pixelRef()) {
+ SkASSERT(fWeOwnThePixels);
+ if (kDiscard_ContentChangeMode == mode) {
+ fBitmap.setPixelRef(NULL, 0);
+ fBitmap.allocPixels();
+ } else {
+ SkBitmap prev(fBitmap);
+ prev.deepCopyTo(&fBitmap, prev.config());
+ }
+ // Now fBitmap is a deep copy of itself (and therefore different from
+ // what is being used by the image. Next we update the canvas to use
+ // this as its backend, so we can't modify the image's pixels anymore.
+ SkASSERT(NULL != this->getCachedCanvas());
+ this->getCachedCanvas()->getDevice()->replaceBitmapBackendForRasterSurface(fBitmap);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+SkSurface* SkSurface::NewRasterDirect(const SkImage::Info& info, void* pixels, size_t rowBytes) {
+ if (!SkSurface_Raster::Valid(info, rowBytes)) {
+ return NULL;
+ }
+ if (NULL == pixels) {
+ return NULL;
+ }
+
+ return SkNEW_ARGS(SkSurface_Raster, (info, pixels, rowBytes));
+}
+
+SkSurface* SkSurface::NewRaster(const SkImage::Info& info) {
+ if (!SkSurface_Raster::Valid(info)) {
+ return NULL;
+ }
+
+ static const size_t kMaxTotalSize = SK_MaxS32;
+ size_t rowBytes = SkImageMinRowBytes(info);
+ uint64_t size64 = (uint64_t)info.fHeight * rowBytes;
+ if (size64 > kMaxTotalSize) {
+ return NULL;
+ }
+
+ size_t size = (size_t)size64;
+ void* pixels = sk_malloc_throw(size);
+ if (NULL == pixels) {
+ return NULL;
+ }
+
+ SkAutoTUnref<SkPixelRef> pr(SkNEW_ARGS(SkMallocPixelRef, (pixels, size, NULL, true)));
+ return SkNEW_ARGS(SkSurface_Raster, (info, pr, rowBytes));
+}