diff options
Diffstat (limited to 'image')
-rw-r--r-- | image/SkDataPixelRef.cpp | 39 | ||||
-rw-r--r-- | image/SkDataPixelRef.h | 35 | ||||
-rw-r--r-- | image/SkImage.cpp | 54 | ||||
-rw-r--r-- | image/SkImagePriv.cpp | 173 | ||||
-rw-r--r-- | image/SkImagePriv.h | 74 | ||||
-rw-r--r-- | image/SkImage_Base.h | 30 | ||||
-rw-r--r-- | image/SkImage_Codec.cpp | 78 | ||||
-rw-r--r-- | image/SkImage_Gpu.cpp | 78 | ||||
-rw-r--r-- | image/SkImage_Picture.cpp | 66 | ||||
-rw-r--r-- | image/SkImage_Raster.cpp | 171 | ||||
-rw-r--r-- | image/SkSurface.cpp | 111 | ||||
-rw-r--r-- | image/SkSurface_Base.h | 96 | ||||
-rw-r--r-- | image/SkSurface_Gpu.cpp | 138 | ||||
-rw-r--r-- | image/SkSurface_Picture.cpp | 92 | ||||
-rw-r--r-- | image/SkSurface_Raster.cpp | 180 |
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)); +} |