From 473f0aa2bb218e50fce5e19063f8c8fdaf57fad4 Mon Sep 17 00:00:00 2001 From: "reed@google.com" Date: Fri, 6 Dec 2013 20:31:45 +0000 Subject: [PATCH] Revert "Revert "PixelRef now returns (nearly) everything that is currently in SkBitmap. The goal is to refactor bitmap later to remove redundancy, and more interestingly, remove the chance for a disconnect between the actual (pixelref) rowbytes and config, and the one claimed by the bitmap."" This reverts commit 4174afb18a9746bbad2a06c0ec2d4ad35f72d790. BUG= Review URL: https://codereview.chromium.org/108723003 git-svn-id: http://skia.googlecode.com/svn/trunk@12547 2bbb7eff-a529-9590-31e7-b0007b416f81 --- include/core/SkBitmap.h | 7 ++ include/core/SkBitmapDevice.h | 2 + include/core/SkImageInfo.h | 19 +++ include/core/SkMallocPixelRef.h | 51 +++++--- include/core/SkPicture.h | 3 +- include/core/SkPixelRef.h | 81 ++++++++++--- include/gpu/GrSurface.h | 3 + include/gpu/SkGr.h | 1 + include/gpu/SkGrPixelRef.h | 11 +- include/images/SkImageRef.h | 7 +- include/images/SkImageRef_GlobalPool.h | 2 +- samplecode/SamplePicture.cpp | 4 +- src/core/SkBitmap.cpp | 98 +++++++++++++-- src/core/SkBitmapDevice.cpp | 35 +++--- src/core/SkImageFilterUtils.cpp | 16 ++- src/core/SkMallocPixelRef.cpp | 135 +++++++++++++++++---- src/core/SkMaskFilter.cpp | 8 +- src/core/SkPixelRef.cpp | 75 +++++++++--- src/effects/gradients/SkGradientShader.cpp | 14 +-- src/gpu/GrSurface.cpp | 10 ++ src/gpu/SkGpuDevice.cpp | 28 +++-- src/gpu/SkGr.cpp | 30 +++++ src/gpu/SkGrPixelRef.cpp | 34 ++++-- src/image/SkDataPixelRef.cpp | 25 ++-- src/image/SkDataPixelRef.h | 7 +- src/image/SkImage_Raster.cpp | 6 +- src/image/SkSurface_Raster.cpp | 16 +-- src/images/SkImageRef.cpp | 31 ++--- src/images/SkImageRef_GlobalPool.cpp | 6 +- src/images/SkImageRef_ashmem.cpp | 8 +- src/images/SkImageRef_ashmem.h | 2 +- src/lazy/SkCachingPixelRef.cpp | 34 +++--- src/lazy/SkCachingPixelRef.h | 4 +- src/lazy/SkDiscardablePixelRef.cpp | 38 +++--- src/lazy/SkDiscardablePixelRef.h | 9 +- tests/PictureTest.cpp | 35 +----- tests/PixelRefTest.cpp | 24 ++-- tests/SerializationTest.cpp | 19 ++- 38 files changed, 660 insertions(+), 278 deletions(-) diff --git a/include/core/SkBitmap.h b/include/core/SkBitmap.h index cd85b6a9b..c0e299ab9 100644 --- a/include/core/SkBitmap.h +++ b/include/core/SkBitmap.h @@ -250,6 +250,13 @@ public: bool setConfig(const SkImageInfo& info, size_t rowBytes = 0); + /** + * If the bitmap's config can be represented as SkImageInfo, return true, + * and if info is not-null, set it to the bitmap's info. If it cannot be + * represented as SkImageInfo, return false and ignore the info parameter. + */ + bool asImageInfo(SkImageInfo* info) const; + /** Use this to assign a new pixel address for an existing bitmap. This will automatically release any pixelref previously installed. Only call this if you are handling ownership/lifetime of the pixel memory. diff --git a/include/core/SkBitmapDevice.h b/include/core/SkBitmapDevice.h index 83f480c60..f3d40d0ce 100644 --- a/include/core/SkBitmapDevice.h +++ b/include/core/SkBitmapDevice.h @@ -258,6 +258,8 @@ private: friend class SkSurface_Raster; + void init(SkBitmap::Config config, int width, int height, bool isOpaque); + // used to change the backend's pixels (and possibly config/rowbytes) // but cannot change the width/height, so there should be no change to // any clip information. diff --git a/include/core/SkImageInfo.h b/include/core/SkImageInfo.h index c22249b84..366d00af7 100644 --- a/include/core/SkImageInfo.h +++ b/include/core/SkImageInfo.h @@ -10,6 +10,9 @@ #include "SkTypes.h" +class SkFlattenableWriteBuffer; +class SkFlattenableReadBuffer; + /** * Describes how to interpret the alpha compoent of a pixel. */ @@ -63,6 +66,7 @@ static inline bool SkAlphaTypeIsOpaque(SkAlphaType at) { enum SkColorType { kAlpha_8_SkColorType, kRGB_565_SkColorType, + kARGB_4444_SkColorType, kRGBA_8888_SkColorType, kBGRA_8888_SkColorType, kIndex8_SkColorType, @@ -82,6 +86,7 @@ static int SkColorTypeBytesPerPixel(SkColorType ct) { static const uint8_t gSize[] = { 1, // Alpha_8 2, // RGB_565 + 2, // ARGB_4444 4, // RGBA_8888 4, // BGRA_8888 1, // kIndex_8 @@ -112,12 +117,26 @@ struct SkImageInfo { return SkColorTypeBytesPerPixel(fColorType); } + size_t minRowBytes() const { + return fWidth * this->bytesPerPixel(); + } + bool operator==(const SkImageInfo& other) const { return 0 == memcmp(this, &other, sizeof(other)); } bool operator!=(const SkImageInfo& other) const { return 0 != memcmp(this, &other, sizeof(other)); } + + void unflatten(SkFlattenableReadBuffer&); + void flatten(SkFlattenableWriteBuffer&) const; + + size_t getSafeSize(size_t rowBytes) const { + if (0 == fHeight) { + return 0; + } + return (fHeight - 1) * rowBytes + fWidth * this->bytesPerPixel(); + } }; #endif diff --git a/include/core/SkMallocPixelRef.h b/include/core/SkMallocPixelRef.h index 100a15d90..5ef70d69b 100644 --- a/include/core/SkMallocPixelRef.h +++ b/include/core/SkMallocPixelRef.h @@ -17,33 +17,52 @@ */ class SkMallocPixelRef : public SkPixelRef { public: - /** Allocate the specified buffer for pixels. The memory is freed when the - last owner of this pixelref is gone. If addr is NULL, sk_malloc_throw() - is called to allocate it. + /** + * Return a new SkMallocPixelRef with the provided pixel storage, rowBytes, + * and optional colortable. The caller is responsible for managing the + * lifetime of the pixel storage buffer, as the pixelref will not try + * to delete the storage. + * + * This pixelref will ref() the specified colortable (if not NULL). + * + * Returns NULL on failure. */ - SkMallocPixelRef(void* addr, size_t size, SkColorTable* ctable, bool ownPixels = true); - virtual ~SkMallocPixelRef(); + static SkMallocPixelRef* NewDirect(const SkImageInfo&, void* addr, + size_t rowBytes, SkColorTable*); + + /** + * Return a new SkMallocPixelRef, automatically allocating storage for the + * pixels. If rowBytes are 0, an optimal value will be chosen automatically. + * If rowBytes is > 0, then it will be respected, or NULL will be returned + * if rowBytes is invalid for the specified info. + * + * This pixelref will ref() the specified colortable (if not NULL). + * + * Returns NULL on failure. + */ + static SkMallocPixelRef* NewAllocate(const SkImageInfo& info, + size_t rowBytes, SkColorTable*); void* getAddr() const { return fStorage; } SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkMallocPixelRef) protected: - // overrides from SkPixelRef - virtual void* onLockPixels(SkColorTable**); - virtual void onUnlockPixels(); + virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE; + virtual void onUnlockPixels() SK_OVERRIDE; + virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; + virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE; SkMallocPixelRef(SkFlattenableReadBuffer& buffer); - virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; - - // Returns the allocation size for the pixels - virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE { return fSize; } + SkMallocPixelRef(const SkImageInfo&, void* addr, size_t rb, SkColorTable*, + bool ownsPixels); + virtual ~SkMallocPixelRef(); private: - void* fStorage; - size_t fSize; - SkColorTable* fCTable; - bool fOwnPixels; + void* fStorage; + SkColorTable* fCTable; + size_t fRB; + const bool fOwnPixels; typedef SkPixelRef INHERITED; }; diff --git a/include/core/SkPicture.h b/include/core/SkPicture.h index bce343ec0..cd6b3bcbb 100644 --- a/include/core/SkPicture.h +++ b/include/core/SkPicture.h @@ -220,10 +220,11 @@ protected: // V14: Add flags word to PathRef serialization // V15: Remove A1 bitmpa config (and renumber remaining configs) // V16: Move SkPath's isOval flag to SkPathRef + // V17: Changes to PixelRef to store SkImageInfo #ifndef DELETE_THIS_CODE_WHEN_SKPS_ARE_REBUILT_AT_V16_AND_ALL_OTHER_INSTANCES_TOO static const uint32_t PRIOR_PICTURE_VERSION = 15; // TODO: remove when .skps regenerated #endif - static const uint32_t PICTURE_VERSION = 16; + static const uint32_t PICTURE_VERSION = 17; // fPlayback, fRecord, fWidth & fHeight are protected to allow derived classes to // install their own SkPicturePlayback-derived players,SkPictureRecord-derived diff --git a/include/core/SkPixelRef.h b/include/core/SkPixelRef.h index 4c564e40c..d03c31a68 100644 --- a/include/core/SkPixelRef.h +++ b/include/core/SkPixelRef.h @@ -14,8 +14,11 @@ #include "SkRefCnt.h" #include "SkString.h" #include "SkFlattenable.h" +#include "SkImageInfo.h" #include "SkTDArray.h" +#define SK_SUPPORT_LEGACY_ONLOCKPIXELS + #ifdef SK_DEBUG /** * Defining SK_IGNORE_PIXELREF_SETPRELOCKED will force all pixelref @@ -49,18 +52,35 @@ class SK_API SkPixelRef : public SkFlattenable { public: SK_DECLARE_INST_COUNT(SkPixelRef) - explicit SkPixelRef(SkBaseMutex* mutex = NULL); + explicit SkPixelRef(const SkImageInfo&); + SkPixelRef(const SkImageInfo&, SkBaseMutex* mutex); virtual ~SkPixelRef(); + const SkImageInfo& info() const { + return fInfo; + } + /** Return the pixel memory returned from lockPixels, or null if the lockCount is 0. */ - void* pixels() const { return fPixels; } + void* pixels() const { return fRec.fPixels; } /** Return the current colorTable (if any) if pixels are locked, or null. */ - SkColorTable* colorTable() const { return fColorTable; } + SkColorTable* colorTable() const { return fRec.fColorTable; } + /** + * To access the actual pixels of a pixelref, it must be "locked". + * Calling lockPixels returns a LockRec struct (on success). + */ + struct LockRec { + void* fPixels; + SkColorTable* fColorTable; + size_t fRowBytes; + + void zero() { sk_bzero(this, sizeof(*this)); } + }; + /** * Returns true if the lockcount > 0 */ @@ -68,10 +88,19 @@ public: SkDEBUGCODE(int getLockCount() const { return fLockCount; }) - /** Call to access the pixel memory, which is returned. Balance with a call - to unlockPixels(). - */ - void lockPixels(); + /** + * Call to access the pixel memory. Return true on success. Balance this + * with a call to unlockPixels(). + */ + bool lockPixels(); + + /** + * Call to access the pixel memory. On success, return true and fill out + * the specified rec. On failure, return false and ignore the rec parameter. + * Balance this with a call to unlockPixels(). + */ + bool lockPixels(LockRec* rec); + /** Call to balanace a previous call to lockPixels(). Returns the pixels (or null) after the unlock. NOTE: lock calls can be nested, but the matching number of unlock calls must be made in order to free the @@ -228,14 +257,28 @@ public: void addGenIDChangeListener(GenIDChangeListener* listener); protected: - /** Called when the lockCount goes from 0 to 1. The caller will have already - acquire a mutex for thread safety, so this method need not do that. - */ - virtual void* onLockPixels(SkColorTable**) = 0; - /** Called when the lock count goes from 1 to 0. The caller will have - already acquire a mutex for thread safety, so this method need not do - that. - */ +#ifdef SK_SUPPORT_LEGACY_ONLOCKPIXELS + virtual void* onLockPixels(SkColorTable**); + virtual bool onNewLockPixels(LockRec*); +#else + /** + * On success, returns true and fills out the LockRec for the pixels. On + * failure returns false and ignores the LockRec parameter. + * + * The caller will have already acquired a mutex for thread safety, so this + * method need not do that. + */ + virtual bool onNewLockPixels(LockRec*) = 0; +#endif + + /** + * Balancing the previous successful call to onNewLockPixels. The locked + * pixel address will no longer be referenced, so the subclass is free to + * move or discard that memory. + * + * The caller will have already acquired a mutex for thread safety, so this + * method need not do that. + */ virtual void onUnlockPixels() = 0; /** Default impl returns true */ @@ -279,12 +322,14 @@ protected: // only call from constructor. Flags this to always be locked, removing // the need to grab the mutex and call onLockPixels/onUnlockPixels. // Performance tweak to avoid those calls (esp. in multi-thread use case). - void setPreLocked(void* pixels, SkColorTable* ctable); + void setPreLocked(void*, size_t rowBytes, SkColorTable*); private: SkBaseMutex* fMutex; // must remain in scope for the life of this object - void* fPixels; - SkColorTable* fColorTable; // we do not track ownership, subclass does + SkImageInfo fInfo; + + // LockRec is only valid if we're in a locked state (isLocked()) + LockRec fRec; int fLockCount; mutable uint32_t fGenerationID; diff --git a/include/gpu/GrSurface.h b/include/gpu/GrSurface.h index c401a905f..15e44ab59 100644 --- a/include/gpu/GrSurface.h +++ b/include/gpu/GrSurface.h @@ -15,6 +15,7 @@ class GrTexture; class GrRenderTarget; +struct SkImageInfo; class GrSurface : public GrResource { public: @@ -58,6 +59,8 @@ public: */ const GrTextureDesc& desc() const { return fDesc; } + void asImageInfo(SkImageInfo*) const; + /** * @return the texture associated with the surface, may be NULL. */ diff --git a/include/gpu/SkGr.h b/include/gpu/SkGr.h index 5e5ca4b72..db08548f5 100644 --- a/include/gpu/SkGr.h +++ b/include/gpu/SkGr.h @@ -50,6 +50,7 @@ GR_STATIC_ASSERT((int)kIDA_GrBlendCoeff == (int)SkXfermode::kIDA_Coeff); * kUnknown_PixelConfig if the conversion cannot be done. */ GrPixelConfig SkBitmapConfig2GrPixelConfig(SkBitmap::Config); +bool GrPixelConfig2ColorType(GrPixelConfig, SkColorType*); static inline GrColor SkColor2GrColor(SkColor c) { SkPMColor pm = SkPreMultiplyColor(c); diff --git a/include/gpu/SkGrPixelRef.h b/include/gpu/SkGrPixelRef.h index da4b8fae0..4d33b9d06 100644 --- a/include/gpu/SkGrPixelRef.h +++ b/include/gpu/SkGrPixelRef.h @@ -23,14 +23,13 @@ */ class SK_API SkROLockPixelsPixelRef : public SkPixelRef { public: - SkROLockPixelsPixelRef(); + SkROLockPixelsPixelRef(const SkImageInfo&); virtual ~SkROLockPixelsPixelRef(); protected: - // override from SkPixelRef - virtual void* onLockPixels(SkColorTable** ptr); - virtual void onUnlockPixels(); - virtual bool onLockPixelsAreWritable() const; // return false; + virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE; + virtual void onUnlockPixels() SK_OVERRIDE; + virtual bool onLockPixelsAreWritable() const SK_OVERRIDE; // return false; private: SkBitmap fBitmap; @@ -47,7 +46,7 @@ public: * cache and would like the pixel ref to unlock it in its destructor then transferCacheLock * should be set to true. */ - SkGrPixelRef(GrSurface* surface, bool transferCacheLock = false); + SkGrPixelRef(const SkImageInfo&, GrSurface*, bool transferCacheLock = false); virtual ~SkGrPixelRef(); // override from SkPixelRef diff --git a/include/images/SkImageRef.h b/include/images/SkImageRef.h index 0599a8d96..36f95e64b 100644 --- a/include/images/SkImageRef.h +++ b/include/images/SkImageRef.h @@ -34,7 +34,7 @@ public: @param config The preferred config of the decoded bitmap. @param sampleSize Requested sampleSize for decoding. Defaults to 1. */ - SkImageRef(SkStreamRewindable*, SkBitmap::Config config, int sampleSize = 1, + SkImageRef(const SkImageInfo&, SkStreamRewindable*, int sampleSize = 1, SkBaseMutex* mutex = NULL); virtual ~SkImageRef(); @@ -72,9 +72,9 @@ protected: When these are called, we will have already acquired the mutex! */ - virtual void* onLockPixels(SkColorTable**); + virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE; // override this in your subclass to clean up when we're unlocking pixels - virtual void onUnlockPixels() {} + virtual void onUnlockPixels() SK_OVERRIDE {} SkImageRef(SkFlattenableReadBuffer&, SkBaseMutex* mutex = NULL); virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; @@ -89,7 +89,6 @@ private: SkImageDecoderFactory* fFactory; // may be null SkStreamRewindable* fStream; - SkBitmap::Config fConfig; int fSampleSize; bool fDoDither; bool fErrorInDecoding; diff --git a/include/images/SkImageRef_GlobalPool.h b/include/images/SkImageRef_GlobalPool.h index 3adc0f615..caaf2487d 100644 --- a/include/images/SkImageRef_GlobalPool.h +++ b/include/images/SkImageRef_GlobalPool.h @@ -15,7 +15,7 @@ class SkImageRef_GlobalPool : public SkImageRef { public: // if pool is null, use the global pool - SkImageRef_GlobalPool(SkStreamRewindable*, SkBitmap::Config, + SkImageRef_GlobalPool(const SkImageInfo&, SkStreamRewindable*, int sampleSize = 1); virtual ~SkImageRef_GlobalPool(); diff --git a/samplecode/SamplePicture.cpp b/samplecode/SamplePicture.cpp index 66289affe..2f7d691d1 100644 --- a/samplecode/SamplePicture.cpp +++ b/samplecode/SamplePicture.cpp @@ -40,7 +40,9 @@ static SkBitmap load_bitmap() { if (SkImageDecoder::DecodeStream(stream, &bm, SkBitmap::kNo_Config, SkImageDecoder::kDecodeBounds_Mode)) { - SkPixelRef* pr = new SkImageRef_GlobalPool(stream, bm.config(), 1); + SkImageInfo info; + bm.asImageInfo(&info); + SkPixelRef* pr = new SkImageRef_GlobalPool(info, stream, 1); bm.setPixelRef(pr)->unref(); } } diff --git a/src/core/SkBitmap.cpp b/src/core/SkBitmap.cpp index 7e204f22d..66271059e 100644 --- a/src/core/SkBitmap.cpp +++ b/src/core/SkBitmap.cpp @@ -361,6 +361,48 @@ void SkBitmap::updatePixelsFromRef() const { } } +static bool config_to_colorType(SkBitmap::Config config, SkColorType* ctOut) { + SkColorType ct; + switch (config) { + case SkBitmap::kA8_Config: + ct = kAlpha_8_SkColorType; + break; + case SkBitmap::kIndex8_Config: + ct = kIndex8_SkColorType; + break; + case SkBitmap::kRGB_565_Config: + ct = kRGB_565_SkColorType; + break; + case SkBitmap::kARGB_4444_Config: + ct = kARGB_4444_SkColorType; + break; + case SkBitmap::kARGB_8888_Config: + ct = kPMColor_SkColorType; + break; + case SkBitmap::kNo_Config: + default: + return false; + } + if (ctOut) { + *ctOut = ct; + } + return true; +} + +bool SkBitmap::asImageInfo(SkImageInfo* info) const { + SkColorType ct; + if (!config_to_colorType(this->config(), &ct)) { + return false; + } + if (info) { + info->fWidth = fWidth; + info->fHeight = fHeight; + info->fAlphaType = this->alphaType(); + info->fColorType = ct; + } + return true; +} + SkPixelRef* SkBitmap::setPixelRef(SkPixelRef* pr, size_t offset) { // do this first, we that we never have a non-zero offset with a null ref if (NULL == pr) { @@ -411,10 +453,20 @@ void SkBitmap::setPixels(void* p, SkColorTable* ctable) { return; } - Sk64 size = this->getSize64(); - SkASSERT(!size.isNeg() && size.is32()); + SkImageInfo info; + if (!this->asImageInfo(&info)) { + this->setPixelRef(NULL, 0); + return; + } + + SkPixelRef* pr = SkMallocPixelRef::NewDirect(info, p, fRowBytes, ctable); + if (NULL == pr) { + this->setPixelRef(NULL, 0); + return; + } + + this->setPixelRef(pr)->unref(); - this->setPixelRef(new SkMallocPixelRef(p, size.get32(), ctable, false))->unref(); // since we're already allocated, we lockPixels right away this->lockPixels(); SkDEBUGCODE(this->validate();) @@ -479,17 +531,19 @@ GrTexture* SkBitmap::getTexture() const { */ bool SkBitmap::HeapAllocator::allocPixelRef(SkBitmap* dst, SkColorTable* ctable) { - Sk64 size = dst->getSize64(); - if (size.isNeg() || !size.is32()) { + SkImageInfo info; + if (!dst->asImageInfo(&info)) { +// SkDebugf("unsupported config for info %d\n", dst->config()); + return false; + } + + SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(), + ctable); + if (NULL == pr) { return false; } - void* addr = sk_malloc_flags(size.get32(), 0); // returns NULL on failure - if (NULL == addr) { - return false; - } - - dst->setPixelRef(new SkMallocPixelRef(addr, size.get32(), ctable))->unref(); + dst->setPixelRef(pr, 0)->unref(); // since we're already allocated, we lockPixels right away dst->lockPixels(); return true; @@ -1599,6 +1653,28 @@ SkBitmap::RLEPixels::~RLEPixels() { /////////////////////////////////////////////////////////////////////////////// +void SkImageInfo::unflatten(SkFlattenableReadBuffer& buffer) { + fWidth = buffer.read32(); + fHeight = buffer.read32(); + + uint32_t packed = buffer.read32(); + SkASSERT(0 == (packed >> 16)); + fAlphaType = (SkAlphaType)((packed >> 8) & 0xFF); + fColorType = (SkColorType)((packed >> 0) & 0xFF); +} + +void SkImageInfo::flatten(SkFlattenableWriteBuffer& buffer) const { + buffer.write32(fWidth); + buffer.write32(fHeight); + + SkASSERT(0 == (fAlphaType & ~0xFF)); + SkASSERT(0 == (fColorType & ~0xFF)); + uint32_t packed = (fAlphaType << 8) | fColorType; + buffer.write32(packed); +} + +/////////////////////////////////////////////////////////////////////////////// + #ifdef SK_DEBUG void SkBitmap::validate() const { SkASSERT(fConfig < kConfigCount); diff --git a/src/core/SkBitmapDevice.cpp b/src/core/SkBitmapDevice.cpp index 1668618cf..368c80751 100644 --- a/src/core/SkBitmapDevice.cpp +++ b/src/core/SkBitmapDevice.cpp @@ -24,31 +24,30 @@ SkBitmapDevice::SkBitmapDevice(const SkBitmap& bitmap, const SkDeviceProperties& , fBitmap(bitmap) { } -SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) { +void SkBitmapDevice::init(SkBitmap::Config config, int width, int height, bool isOpaque) { fBitmap.setConfig(config, width, height, 0, isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType); - if (!fBitmap.allocPixels()) { - fBitmap.setConfig(config, 0, 0, 0, isOpaque ? - kOpaque_SkAlphaType : kPremul_SkAlphaType); - } - if (!isOpaque) { - fBitmap.eraseColor(SK_ColorTRANSPARENT); + + if (SkBitmap::kNo_Config != config) { + if (!fBitmap.allocPixels()) { + // indicate failure by zeroing our bitmap + fBitmap.setConfig(config, 0, 0, 0, isOpaque ? + kOpaque_SkAlphaType : kPremul_SkAlphaType); + } else if (!isOpaque) { + fBitmap.eraseColor(SK_ColorTRANSPARENT); + } } } +SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque) { + this->init(config, width, height, isOpaque); +} + SkBitmapDevice::SkBitmapDevice(SkBitmap::Config config, int width, int height, bool isOpaque, const SkDeviceProperties& deviceProperties) - : SkBaseDevice(deviceProperties) { - - fBitmap.setConfig(config, width, height, 0, isOpaque ? - kOpaque_SkAlphaType : kPremul_SkAlphaType); - if (!fBitmap.allocPixels()) { - fBitmap.setConfig(config, 0, 0, 0, isOpaque ? - kOpaque_SkAlphaType : kPremul_SkAlphaType); - } - if (!isOpaque) { - fBitmap.eraseColor(SK_ColorTRANSPARENT); - } + : SkBaseDevice(deviceProperties) +{ + this->init(config, width, height, isOpaque); } SkBitmapDevice::~SkBitmapDevice() { diff --git a/src/core/SkImageFilterUtils.cpp b/src/core/SkImageFilterUtils.cpp index 8385fb446..e535d934f 100644 --- a/src/core/SkImageFilterUtils.cpp +++ b/src/core/SkImageFilterUtils.cpp @@ -15,8 +15,14 @@ #include "SkGr.h" bool SkImageFilterUtils::WrapTexture(GrTexture* texture, int width, int height, SkBitmap* result) { - result->setConfig(SkBitmap::kARGB_8888_Config, width, height); - result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (texture)))->unref(); + SkImageInfo info; + info.fWidth = width; + info.fHeight = height; + info.fColorType = kPMColor_SkColorType; + info.fAlphaType = kPremul_SkAlphaType; + + result->setConfig(info); + result->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); return true; } @@ -36,8 +42,12 @@ bool SkImageFilterUtils::GetInputResultGPU(SkImageFilter* filter, SkImageFilter: } else { if (filter->filterImage(proxy, src, ctm, result, offset)) { if (!result->getTexture()) { + SkImageInfo info; + if (!result->asImageInfo(&info)) { + return false; + } GrTexture* resultTex = GrLockAndRefCachedBitmapTexture(context, *result, NULL); - result->setPixelRef(new SkGrPixelRef(resultTex))->unref(); + result->setPixelRef(new SkGrPixelRef(info, resultTex))->unref(); GrUnlockAndUnrefCachedBitmapTexture(resultTex); } return true; diff --git a/src/core/SkMallocPixelRef.cpp b/src/core/SkMallocPixelRef.cpp index f229e9de3..4ba6e049d 100644 --- a/src/core/SkMallocPixelRef.cpp +++ b/src/core/SkMallocPixelRef.cpp @@ -1,27 +1,105 @@ - /* * Copyright 2011 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ + #include "SkMallocPixelRef.h" #include "SkBitmap.h" #include "SkFlattenableBuffers.h" -SkMallocPixelRef::SkMallocPixelRef(void* storage, size_t size, - SkColorTable* ctable, bool ownPixels) { - if (NULL == storage) { - SkASSERT(ownPixels); - storage = sk_malloc_throw(size); +static bool check_info(const SkImageInfo& info, SkColorTable* ctable) { + if (info.fWidth < 0 || + info.fHeight < 0 || + (unsigned)info.fColorType > (unsigned)kLastEnum_SkColorType || + (unsigned)info.fAlphaType > (unsigned)kLastEnum_SkAlphaType) + { + return false; } - fStorage = storage; - fSize = size; - fCTable = ctable; - SkSafeRef(ctable); - fOwnPixels = ownPixels; + + // these seem like good checks, but currently we have (at least) tests + // that expect the pixelref to succeed even when there is a mismatch + // with colortables. fix? +#if 0 + if (kIndex8_SkColorType == info.fColorType && NULL == ctable) { + return false; + } + if (kIndex8_SkColorType != info.fColorType && NULL != ctable) { + return false; + } +#endif + return true; +} - this->setPreLocked(fStorage, fCTable); +SkMallocPixelRef* SkMallocPixelRef::NewDirect(const SkImageInfo& info, + void* addr, + size_t rowBytes, + SkColorTable* ctable) { + if (!check_info(info, ctable)) { + return NULL; + } + return SkNEW_ARGS(SkMallocPixelRef, (info, addr, rowBytes, ctable, false)); +} + +SkMallocPixelRef* SkMallocPixelRef::NewAllocate(const SkImageInfo& info, + size_t requestedRowBytes, + SkColorTable* ctable) { + if (!check_info(info, ctable)) { + return NULL; + } + + int32_t minRB = info.minRowBytes(); + if (minRB < 0) { + return NULL; // allocation will be too large + } + if (requestedRowBytes > 0 && (int32_t)requestedRowBytes < minRB) { + return NULL; // cannot meet requested rowbytes + } + + int32_t rowBytes; + if (requestedRowBytes) { + rowBytes = requestedRowBytes; + } else { + rowBytes = minRB; + } + + Sk64 bigSize; + bigSize.setMul(info.fHeight, rowBytes); + if (!bigSize.is32()) { + return NULL; + } + + size_t size = bigSize.get32(); + void* addr = sk_malloc_flags(size, 0); + if (NULL == addr) { + return NULL; + } + + return SkNEW_ARGS(SkMallocPixelRef, (info, addr, rowBytes, ctable, true)); +} + +/////////////////////////////////////////////////////////////////////////////// + +SkMallocPixelRef::SkMallocPixelRef(const SkImageInfo& info, void* storage, + size_t rowBytes, SkColorTable* ctable, + bool ownsPixels) + : SkPixelRef(info) + , fOwnPixels(ownsPixels) +{ + SkASSERT(check_info(info, ctable)); + SkASSERT(rowBytes >= info.minRowBytes()); + + if (kIndex8_SkColorType != info.fColorType) { + ctable = NULL; + } + + fStorage = storage; + fCTable = ctable; + fRB = rowBytes; + SkSafeRef(ctable); + + this->setPreLocked(fStorage, fRB, fCTable); } SkMallocPixelRef::~SkMallocPixelRef() { @@ -31,19 +109,30 @@ SkMallocPixelRef::~SkMallocPixelRef() { } } -void* SkMallocPixelRef::onLockPixels(SkColorTable** ct) { - *ct = fCTable; - return fStorage; +bool SkMallocPixelRef::onNewLockPixels(LockRec* rec) { + rec->fPixels = fStorage; + rec->fRowBytes = fRB; + rec->fColorTable = fCTable; + return true; } void SkMallocPixelRef::onUnlockPixels() { // nothing to do } +size_t SkMallocPixelRef::getAllocatedSizeInBytes() const { + return this->info().getSafeSize(fRB); +} + void SkMallocPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); - buffer.writeByteArray(fStorage, fSize); + buffer.write32(fRB); + + // TODO: replace this bulk write with a chunky one that can trim off any + // trailing bytes on each scanline (in case rowbytes > width*size) + size_t size = this->info().getSafeSize(fRB); + buffer.writeByteArray(fStorage, size); buffer.writeBool(fCTable != NULL); if (fCTable) { fCTable->writeToBuffer(buffer); @@ -51,16 +140,18 @@ void SkMallocPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { } SkMallocPixelRef::SkMallocPixelRef(SkFlattenableReadBuffer& buffer) - : INHERITED(buffer, NULL) { - fSize = buffer.getArrayCount(); - fStorage = sk_malloc_throw(fSize); - buffer.readByteArray(fStorage, fSize); + : INHERITED(buffer, NULL) + , fOwnPixels(true) +{ + fRB = buffer.read32(); + size_t size = this->info().getSafeSize(fRB); + fStorage = sk_malloc_throw(size); + buffer.readByteArray(fStorage, size); if (buffer.readBool()) { fCTable = SkNEW_ARGS(SkColorTable, (buffer)); } else { fCTable = NULL; } - fOwnPixels = true; - this->setPreLocked(fStorage, fCTable); + this->setPreLocked(fStorage, fRB, fCTable); } diff --git a/src/core/SkMaskFilter.cpp b/src/core/SkMaskFilter.cpp index f062f135f..adfed4109 100644 --- a/src/core/SkMaskFilter.cpp +++ b/src/core/SkMaskFilter.cpp @@ -349,10 +349,14 @@ bool SkMaskFilter::filterMaskGPU(GrContext* context, if (!result) { return false; } + SkAutoUnref aur(dst); + SkImageInfo info; resultBM->setConfig(srcBM.config(), dst->width(), dst->height()); - resultBM->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (dst)))->unref(); - dst->unref(); + if (resultBM->asImageInfo(&info)) { + return false; + } + resultBM->setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, dst)))->unref(); return true; } diff --git a/src/core/SkPixelRef.cpp b/src/core/SkPixelRef.cpp index 1afc3360a..60b5cfb26 100644 --- a/src/core/SkPixelRef.cpp +++ b/src/core/SkPixelRef.cpp @@ -82,10 +82,20 @@ void SkPixelRef::setMutex(SkBaseMutex* mutex) { // just need a > 0 value, so pick a funny one to aid in debugging #define SKPIXELREF_PRELOCKED_LOCKCOUNT 123456789 -SkPixelRef::SkPixelRef(SkBaseMutex* mutex) { +SkPixelRef::SkPixelRef(const SkImageInfo& info) { + this->setMutex(NULL); + fInfo = info; + fRec.zero(); + fLockCount = 0; + this->needsNewGenID(); + fIsImmutable = false; + fPreLocked = false; +} + +SkPixelRef::SkPixelRef(const SkImageInfo& info, SkBaseMutex* mutex) { this->setMutex(mutex); - fPixels = NULL; - fColorTable = NULL; // we do not track ownership of this + fInfo = info; + fRec.zero(); fLockCount = 0; this->needsNewGenID(); fIsImmutable = false; @@ -95,8 +105,9 @@ SkPixelRef::SkPixelRef(SkBaseMutex* mutex) { SkPixelRef::SkPixelRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) : INHERITED(buffer) { this->setMutex(mutex); - fPixels = NULL; - fColorTable = NULL; // we do not track ownership of this + + fInfo.unflatten(buffer); + fRec.zero(); fLockCount = 0; fIsImmutable = buffer.readBool(); fGenerationID = buffer.readUInt(); @@ -120,12 +131,13 @@ void SkPixelRef::cloneGenID(const SkPixelRef& that) { that.fUniqueGenerationID = false; } -void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) { +void SkPixelRef::setPreLocked(void* pixels, size_t rowBytes, SkColorTable* ctable) { #ifndef SK_IGNORE_PIXELREF_SETPRELOCKED // only call me in your constructor, otherwise fLockCount tracking can get // out of sync. - fPixels = pixels; - fColorTable = ctable; + fRec.fPixels = pixels; + fRec.fColorTable = ctable; + fRec.fRowBytes = rowBytes; fLockCount = SKPIXELREF_PRELOCKED_LOCKCOUNT; fPreLocked = true; #endif @@ -133,6 +145,8 @@ void SkPixelRef::setPreLocked(void* pixels, SkColorTable* ctable) { void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); + + fInfo.flatten(buffer); buffer.writeBool(fIsImmutable); // We write the gen ID into the picture for within-process recording. This // is safe since the same genID will never refer to two different sets of @@ -147,16 +161,27 @@ void SkPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { } } -void SkPixelRef::lockPixels() { +bool SkPixelRef::lockPixels(LockRec* rec) { SkASSERT(!fPreLocked || SKPIXELREF_PRELOCKED_LOCKCOUNT == fLockCount); - + if (!fPreLocked) { SkAutoMutexAcquire ac(*fMutex); - + if (1 == ++fLockCount) { - fPixels = this->onLockPixels(&fColorTable); + LockRec rec; + if (!this->onNewLockPixels(&rec)) { + return false; + } + fRec = rec; } } + *rec = fRec; + return true; +} + +bool SkPixelRef::lockPixels() { + LockRec rec; + return this->lockPixels(&rec); } void SkPixelRef::unlockPixels() { @@ -168,8 +193,7 @@ void SkPixelRef::unlockPixels() { SkASSERT(fLockCount > 0); if (0 == --fLockCount) { this->onUnlockPixels(); - fPixels = NULL; - fColorTable = NULL; + fRec.zero(); } } } @@ -250,6 +274,29 @@ size_t SkPixelRef::getAllocatedSizeInBytes() const { /////////////////////////////////////////////////////////////////////////////// +#ifdef SK_SUPPORT_LEGACY_ONLOCKPIXELS + +void* SkPixelRef::onLockPixels(SkColorTable** ctable) { + return NULL; +} + +bool SkPixelRef::onNewLockPixels(LockRec* rec) { + SkColorTable* ctable; + void* pixels = this->onLockPixels(&ctable); + if (!pixels) { + return false; + } + + rec->fPixels = pixels; + rec->fColorTable = ctable; + rec->fRowBytes = 0; // callers don't currently need this (thank goodness) + return true; +} + +#endif + +/////////////////////////////////////////////////////////////////////////////// + #ifdef SK_BUILD_FOR_ANDROID void SkPixelRef::globalRef(void* data) { this->ref(); diff --git a/src/effects/gradients/SkGradientShader.cpp b/src/effects/gradients/SkGradientShader.cpp index 277619934..5d200d18d 100644 --- a/src/effects/gradients/SkGradientShader.cpp +++ b/src/effects/gradients/SkGradientShader.cpp @@ -513,13 +513,14 @@ const uint16_t* SkGradientShaderBase::getCache16() const { const SkPMColor* SkGradientShaderBase::getCache32() const { if (fCache32 == NULL) { - // double the count for dither entries - const int entryCount = kCache32Count * 4; - const size_t allocSize = sizeof(SkPMColor) * entryCount; + SkImageInfo info; + info.fWidth = kCache32Count; + info.fHeight = 4; // for our 4 dither rows + info.fAlphaType = kPremul_SkAlphaType; + info.fColorType = kPMColor_SkColorType; if (NULL == fCache32PixelRef) { - fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef, - (NULL, allocSize, NULL)); + fCache32PixelRef = SkMallocPixelRef::NewAllocate(info, 0, NULL); } fCache32 = (SkPMColor*)fCache32PixelRef->getAddr(); if (fColorCount == 2) { @@ -541,8 +542,7 @@ const SkPMColor* SkGradientShaderBase::getCache32() const { } if (fMapper) { - SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef, - (NULL, allocSize, NULL)); + SkMallocPixelRef* newPR = SkMallocPixelRef::NewAllocate(info, 0, NULL); SkPMColor* linear = fCache32; // just computed linear data SkPMColor* mapped = (SkPMColor*)newPR->getAddr(); // storage for mapped data SkUnitMapper* map = fMapper; diff --git a/src/gpu/GrSurface.cpp b/src/gpu/GrSurface.cpp index fed95f232..1fcc4ff18 100644 --- a/src/gpu/GrSurface.cpp +++ b/src/gpu/GrSurface.cpp @@ -8,9 +8,19 @@ #include "GrSurface.h" #include "SkBitmap.h" +#include "SkGr.h" #include "SkImageEncoder.h" #include +void GrSurface::asImageInfo(SkImageInfo* info) const { + if (!GrPixelConfig2ColorType(this->config(), &info->fColorType)) { + sk_throw(); + } + info->fWidth = this->width(); + info->fHeight = this->height(); + info->fAlphaType = kPremul_SkAlphaType; +} + bool GrSurface::savePixels(const char* filename) { SkBitmap bm; bm.setConfig(SkBitmap::kARGB_8888_Config, this->width(), this->height()); diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 07a946ef9..e4c153783 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -200,7 +200,10 @@ void SkGpuDevice::initFromRenderTarget(GrContext* context, if (NULL == surface) { surface = fRenderTarget; } - SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (surface, cached)); + + SkImageInfo info; + surface->asImageInfo(&info); + SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, surface, cached)); this->setPixelRef(pr, 0)->unref(); } @@ -210,8 +213,8 @@ SkGpuDevice::SkGpuDevice(GrContext* context, int width, int height, int sampleCount) - : SkBitmapDevice(config, width, height, false /*isOpaque*/) { - + : SkBitmapDevice(config, width, height, false /*isOpaque*/) +{ fDrawProcs = NULL; fContext = context; @@ -231,6 +234,14 @@ SkGpuDevice::SkGpuDevice(GrContext* context, desc.fConfig = SkBitmapConfig2GrPixelConfig(config); desc.fSampleCnt = sampleCount; + SkImageInfo info; + if (!GrPixelConfig2ColorType(desc.fConfig, &info.fColorType)) { + sk_throw(); + } + info.fWidth = width; + info.fHeight = height; + info.fAlphaType = kPremul_SkAlphaType; + SkAutoTUnref texture(fContext->createUncachedTexture(desc, NULL, 0)); if (NULL != texture) { @@ -240,7 +251,7 @@ SkGpuDevice::SkGpuDevice(GrContext* context, SkASSERT(NULL != fRenderTarget); // wrap the bitmap with a pixelref to expose our texture - SkGrPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (texture)); + SkGrPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (info, texture)); this->setPixelRef(pr, 0)->unref(); } else { GrPrintf("--- failed to create gpu-offscreen [%d %d]\n", @@ -826,11 +837,12 @@ bool create_mask_GPU(GrContext* context, } SkBitmap wrap_texture(GrTexture* texture) { + SkImageInfo info; + texture->asImageInfo(&info); + SkBitmap result; - bool dummy; - SkBitmap::Config config = grConfig2skConfig(texture->config(), &dummy); - result.setConfig(config, texture->width(), texture->height()); - result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (texture)))->unref(); + result.setConfig(info); + result.setPixelRef(SkNEW_ARGS(SkGrPixelRef, (info, texture)))->unref(); return result; } diff --git a/src/gpu/SkGr.cpp b/src/gpu/SkGr.cpp index c7ae0c8f3..b55256e78 100644 --- a/src/gpu/SkGr.cpp +++ b/src/gpu/SkGr.cpp @@ -258,3 +258,33 @@ GrPixelConfig SkBitmapConfig2GrPixelConfig(SkBitmap::Config config) { return kUnknown_GrPixelConfig; } } + +bool GrPixelConfig2ColorType(GrPixelConfig config, SkColorType* ctOut) { + SkColorType ct; + switch (config) { + case kAlpha_8_GrPixelConfig: + ct = kAlpha_8_SkColorType; + break; + case kIndex_8_GrPixelConfig: + ct = kIndex8_SkColorType; + break; + case kRGB_565_GrPixelConfig: + ct = kRGB_565_SkColorType; + break; + case kRGBA_4444_GrPixelConfig: + ct = kARGB_4444_SkColorType; + break; + case kRGBA_8888_GrPixelConfig: + ct = kRGBA_8888_SkColorType; + break; + case kBGRA_8888_GrPixelConfig: + ct = kBGRA_8888_SkColorType; + break; + default: + return false; + } + if (ctOut) { + *ctOut = ct; + } + return true; +} diff --git a/src/gpu/SkGrPixelRef.cpp b/src/gpu/SkGrPixelRef.cpp index dc5d7558f..74b1a4faa 100644 --- a/src/gpu/SkGrPixelRef.cpp +++ b/src/gpu/SkGrPixelRef.cpp @@ -18,24 +18,29 @@ // to avoid deadlock with the default one provided by SkPixelRef. SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex); -SkROLockPixelsPixelRef::SkROLockPixelsPixelRef() : INHERITED(&gROLockPixelsPixelRefMutex) { +SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info) + : INHERITED(info, &gROLockPixelsPixelRefMutex) { } SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() { } -void* SkROLockPixelsPixelRef::onLockPixels(SkColorTable** ctable) { - if (ctable) { - *ctable = NULL; - } +bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) { fBitmap.reset(); // SkDebugf("---------- calling readpixels in support of lockpixels\n"); if (!this->onReadPixels(&fBitmap, NULL)) { SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n"); - return NULL; + return false; } fBitmap.lockPixels(); - return fBitmap.getPixels(); + if (NULL == fBitmap.getPixels()) { + return false; + } + + rec->fPixels = fBitmap.getPixels(); + rec->fColorTable = NULL; + rec->fRowBytes = fBitmap.rowBytes(); + return true; } void SkROLockPixelsPixelRef::onUnlockPixels() { @@ -76,6 +81,14 @@ static SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkBitmap::Config desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; desc.fConfig = SkBitmapConfig2GrPixelConfig(dstConfig); + SkImageInfo info; + if (!GrPixelConfig2ColorType(desc.fConfig, &info.fColorType)) { + return NULL; + } + info.fWidth = desc.fWidth; + info.fHeight = desc.fHeight; + info.fAlphaType = kPremul_SkAlphaType; + GrTexture* dst = context->createUncachedTexture(desc, NULL, 0); if (NULL == dst) { return NULL; @@ -93,14 +106,17 @@ static SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkBitmap::Config dst->releaseRenderTarget(); #endif - SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (dst)); + SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst)); SkSafeUnref(dst); return pixelRef; } /////////////////////////////////////////////////////////////////////////////// -SkGrPixelRef::SkGrPixelRef(GrSurface* surface, bool transferCacheLock) { +SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface, + bool transferCacheLock) + : INHERITED(info) +{ // TODO: figure out if this is responsible for Chrome canvas errors #if 0 // The GrTexture has a ref to the GrRenderTarget but not vice versa. diff --git a/src/image/SkDataPixelRef.cpp b/src/image/SkDataPixelRef.cpp index 7897bf931..875f933b9 100644 --- a/src/image/SkDataPixelRef.cpp +++ b/src/image/SkDataPixelRef.cpp @@ -9,18 +9,25 @@ #include "SkData.h" #include "SkFlattenableBuffers.h" -SkDataPixelRef::SkDataPixelRef(SkData* data) : fData(data) { +SkDataPixelRef::SkDataPixelRef(const SkImageInfo& info, + SkData* data, size_t rowBytes) + : INHERITED(info) + , fData(data) + , fRB(rowBytes) +{ fData->ref(); - this->setPreLocked(const_cast(fData->data()), NULL); + this->setPreLocked(const_cast(fData->data()), rowBytes, NULL); } SkDataPixelRef::~SkDataPixelRef() { fData->unref(); } -void* SkDataPixelRef::onLockPixels(SkColorTable** ct) { - *ct = NULL; - return const_cast(fData->data()); +bool SkDataPixelRef::onNewLockPixels(LockRec* rec) { + rec->fPixels = const_cast(fData->data()); + rec->fColorTable = NULL; + rec->fRowBytes = fRB; + return true; } void SkDataPixelRef::onUnlockPixels() { @@ -33,11 +40,15 @@ size_t SkDataPixelRef::getAllocatedSizeInBytes() const { void SkDataPixelRef::flatten(SkFlattenableWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); + buffer.writeDataAsByteArray(fData); + buffer.write32(fRB); } SkDataPixelRef::SkDataPixelRef(SkFlattenableReadBuffer& buffer) - : INHERITED(buffer, NULL) { + : INHERITED(buffer, NULL) +{ fData = buffer.readByteArrayAsData(); - this->setPreLocked(const_cast(fData->data()), NULL); + fRB = buffer.read32(); + this->setPreLocked(const_cast(fData->data()), fRB, NULL); } diff --git a/src/image/SkDataPixelRef.h b/src/image/SkDataPixelRef.h index 50c885714..c2e52cd9e 100644 --- a/src/image/SkDataPixelRef.h +++ b/src/image/SkDataPixelRef.h @@ -14,13 +14,13 @@ class SkData; class SkDataPixelRef : public SkPixelRef { public: - SkDataPixelRef(SkData* data); + SkDataPixelRef(const SkImageInfo&, SkData* data, size_t rowBytes); virtual ~SkDataPixelRef(); SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkDataPixelRef) protected: - virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE; + virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE; virtual void onUnlockPixels() SK_OVERRIDE; virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE; @@ -28,7 +28,8 @@ protected: virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE; private: - SkData* fData; + SkData* fData; + size_t fRB; typedef SkPixelRef INHERITED; }; diff --git a/src/image/SkImage_Raster.cpp b/src/image/SkImage_Raster.cpp index a872ae36e..93de5ea3a 100644 --- a/src/image/SkImage_Raster.cpp +++ b/src/image/SkImage_Raster.cpp @@ -84,10 +84,8 @@ SkImage* SkImage_Raster::NewEmpty() { SkImage_Raster::SkImage_Raster(const Info& info, SkData* data, size_t rowBytes) : INHERITED(info.fWidth, info.fHeight) { - SkBitmap::Config config = SkImageInfoToBitmapConfig(info); - - fBitmap.setConfig(config, info.fWidth, info.fHeight, rowBytes, info.fAlphaType); - fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (data)))->unref(); + fBitmap.setConfig(info, rowBytes); + fBitmap.setPixelRef(SkNEW_ARGS(SkDataPixelRef, (info, data, rowBytes)))->unref(); fBitmap.setImmutable(); } diff --git a/src/image/SkSurface_Raster.cpp b/src/image/SkSurface_Raster.cpp index 27db504df..61ade6f46 100644 --- a/src/image/SkSurface_Raster.cpp +++ b/src/image/SkSurface_Raster.cpp @@ -155,19 +155,9 @@ SkSurface* SkSurface::NewRaster(const SkImageInfo& 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) { + SkAutoTUnref pr(SkMallocPixelRef::NewAllocate(info, 0, NULL)); + if (NULL == pr.get()) { return NULL; } - - size_t size = (size_t)size64; - void* pixels = sk_malloc_throw(size); - if (NULL == pixels) { - return NULL; - } - - SkAutoTUnref pr(SkNEW_ARGS(SkMallocPixelRef, (pixels, size, NULL, true))); - return SkNEW_ARGS(SkSurface_Raster, (info, pr, rowBytes)); + return SkNEW_ARGS(SkSurface_Raster, (info, pr, info.minRowBytes())); } diff --git a/src/images/SkImageRef.cpp b/src/images/SkImageRef.cpp index 1a8284bdd..99782c45c 100644 --- a/src/images/SkImageRef.cpp +++ b/src/images/SkImageRef.cpp @@ -15,16 +15,14 @@ //#define DUMP_IMAGEREF_LIFECYCLE - /////////////////////////////////////////////////////////////////////////////// -SkImageRef::SkImageRef(SkStreamRewindable* stream, SkBitmap::Config config, +SkImageRef::SkImageRef(const SkImageInfo& info, SkStreamRewindable* stream, int sampleSize, SkBaseMutex* mutex) - : SkPixelRef(mutex), fErrorInDecoding(false) { + : INHERITED(info, mutex), fErrorInDecoding(false) { SkASSERT(stream); stream->ref(); fStream = stream; - fConfig = config; fSampleSize = sampleSize; fDoDither = true; fPrev = fNext = NULL; @@ -40,7 +38,7 @@ SkImageRef::~SkImageRef() { #ifdef DUMP_IMAGEREF_LIFECYCLE SkDebugf("delete ImageRef %p [%d] data=%d\n", - this, fConfig, (int)fStream->getLength()); + this, this->info().fColorType, (int)fStream->getLength()); #endif fStream->unref(); @@ -92,14 +90,6 @@ bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) { return false; } - /* As soon as we really know our config, we record it, so that on - subsequent calls to the codec, we are sure we will always get the same - result. - */ - if (SkBitmap::kNo_Config != fBitmap.config()) { - fConfig = fBitmap.config(); - } - if (NULL != fBitmap.getPixels() || (SkBitmap::kNo_Config != fBitmap.config() && SkImageDecoder::kDecodeBounds_Mode == mode)) { @@ -125,7 +115,7 @@ bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) { codec->setSampleSize(fSampleSize); codec->setDitherImage(fDoDither); - if (this->onDecode(codec, fStream, &fBitmap, fConfig, mode)) { + if (this->onDecode(codec, fStream, &fBitmap, fBitmap.config(), mode)) { return true; } } @@ -143,15 +133,18 @@ bool SkImageRef::prepareBitmap(SkImageDecoder::Mode mode) { return false; } -void* SkImageRef::onLockPixels(SkColorTable** ct) { +bool SkImageRef::onNewLockPixels(LockRec* rec) { if (NULL == fBitmap.getPixels()) { (void)this->prepareBitmap(SkImageDecoder::kDecodePixels_Mode); } - if (ct) { - *ct = fBitmap.getColorTable(); + if (NULL == fBitmap.getPixels()) { + return false; } - return fBitmap.getPixels(); + rec->fPixels = fBitmap.getPixels(); + rec->fColorTable = NULL; + rec->fRowBytes = fBitmap.rowBytes(); + return true; } size_t SkImageRef::ramUsed() const { @@ -170,7 +163,6 @@ size_t SkImageRef::ramUsed() const { SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) : INHERITED(buffer, mutex), fErrorInDecoding(false) { - fConfig = (SkBitmap::Config)buffer.readUInt(); fSampleSize = buffer.readInt(); fDoDither = buffer.readBool(); @@ -185,7 +177,6 @@ SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex) void SkImageRef::flatten(SkFlattenableWriteBuffer& buffer) const { this->INHERITED::flatten(buffer); - buffer.writeUInt(fConfig); buffer.writeInt(fSampleSize); buffer.writeBool(fDoDither); // FIXME: Consider moving this logic should go into writeStream itself. diff --git a/src/images/SkImageRef_GlobalPool.cpp b/src/images/SkImageRef_GlobalPool.cpp index 352dd42d9..f91cebabb 100644 --- a/src/images/SkImageRef_GlobalPool.cpp +++ b/src/images/SkImageRef_GlobalPool.cpp @@ -24,10 +24,10 @@ static SkImageRefPool* GetGlobalPool() { return gPool; } -SkImageRef_GlobalPool::SkImageRef_GlobalPool(SkStreamRewindable* stream, - SkBitmap::Config config, +SkImageRef_GlobalPool::SkImageRef_GlobalPool(const SkImageInfo& info, + SkStreamRewindable* stream, int sampleSize) - : SkImageRef(stream, config, sampleSize, &gGlobalPoolMutex) { + : SkImageRef(info, stream, sampleSize, &gGlobalPoolMutex) { SkASSERT(&gGlobalPoolMutex == this->mutex()); SkAutoMutexAcquire ac(gGlobalPoolMutex); GetGlobalPool()->addToHead(this); diff --git a/src/images/SkImageRef_ashmem.cpp b/src/images/SkImageRef_ashmem.cpp index 0dba1d119..383a487d2 100644 --- a/src/images/SkImageRef_ashmem.cpp +++ b/src/images/SkImageRef_ashmem.cpp @@ -31,10 +31,10 @@ static size_t roundToPageSize(size_t size) { return newsize; } -SkImageRef_ashmem::SkImageRef_ashmem(SkStreamRewindable* stream, - SkBitmap::Config config, - int sampleSize) - : SkImageRef(stream, config, sampleSize) { +SkImageRef_ashmem::SkImageRef_ashmem(const SkImageInfo& info, + SkStreamRewindable* stream, + int sampleSize) + : SkImageRef(info, stream, sampleSize) { fRec.fFD = -1; fRec.fAddr = NULL; diff --git a/src/images/SkImageRef_ashmem.h b/src/images/SkImageRef_ashmem.h index efee5e759..a2652fbc3 100644 --- a/src/images/SkImageRef_ashmem.h +++ b/src/images/SkImageRef_ashmem.h @@ -19,7 +19,7 @@ struct SkAshmemRec { class SkImageRef_ashmem : public SkImageRef { public: - SkImageRef_ashmem(SkStreamRewindable*, SkBitmap::Config, int sampleSize = 1); + SkImageRef_ashmem(const SkImageInfo&, SkStreamRewindable*, int sampleSize = 1); virtual ~SkImageRef_ashmem(); SK_DECLARE_PUBLIC_FLATTENABLE_DESERIALIZATION_PROCS(SkImageRef_ashmem) diff --git a/src/lazy/SkCachingPixelRef.cpp b/src/lazy/SkCachingPixelRef.cpp index 667a94931..fba984556 100644 --- a/src/lazy/SkCachingPixelRef.cpp +++ b/src/lazy/SkCachingPixelRef.cpp @@ -8,7 +8,6 @@ #include "SkCachingPixelRef.h" #include "SkScaledImageCache.h" - bool SkCachingPixelRef::Install(SkImageGenerator* generator, SkBitmap* dst) { SkImageInfo info; @@ -31,10 +30,10 @@ bool SkCachingPixelRef::Install(SkImageGenerator* generator, SkCachingPixelRef::SkCachingPixelRef(SkImageGenerator* generator, const SkImageInfo& info, size_t rowBytes) - : fImageGenerator(generator) + : INHERITED(info) + , fImageGenerator(generator) , fErrorInDecoding(false) , fScaledCacheId(NULL) - , fInfo(info) , fRowBytes(rowBytes) { SkASSERT(fImageGenerator != NULL); } @@ -44,31 +43,32 @@ SkCachingPixelRef::~SkCachingPixelRef() { // Assert always unlock before unref. } -void* SkCachingPixelRef::onLockPixels(SkColorTable** colorTable) { - (void)colorTable; +bool SkCachingPixelRef::onNewLockPixels(LockRec* rec) { if (fErrorInDecoding) { - return NULL; // don't try again. + return false; // don't try again. } + + const SkImageInfo& info = this->info(); SkBitmap bitmap; SkASSERT(NULL == fScaledCacheId); fScaledCacheId = SkScaledImageCache::FindAndLock(this->getGenerationID(), - fInfo.fWidth, - fInfo.fHeight, + info.fWidth, + info.fHeight, &bitmap); if (NULL == fScaledCacheId) { // Cache has been purged, must re-decode. - if ((!bitmap.setConfig(fInfo, fRowBytes)) || !bitmap.allocPixels()) { + if ((!bitmap.setConfig(info, fRowBytes)) || !bitmap.allocPixels()) { fErrorInDecoding = true; - return NULL; + return false; } SkAutoLockPixels autoLockPixels(bitmap); - if (!fImageGenerator->getPixels(fInfo, bitmap.getPixels(), fRowBytes)) { + if (!fImageGenerator->getPixels(info, bitmap.getPixels(), fRowBytes)) { fErrorInDecoding = true; - return NULL; + return false; } fScaledCacheId = SkScaledImageCache::AddAndLock(this->getGenerationID(), - fInfo.fWidth, - fInfo.fHeight, + info.fWidth, + info.fHeight, bitmap); SkASSERT(fScaledCacheId != NULL); } @@ -78,6 +78,7 @@ void* SkCachingPixelRef::onLockPixels(SkColorTable** colorTable) { SkAutoLockPixels autoLockPixels(bitmap); void* pixels = bitmap.getPixels(); SkASSERT(pixels != NULL); + // At this point, the autoLockPixels will unlockPixels() // to remove bitmap's lock on the pixels. We will then // destroy bitmap. The *only* guarantee that this pointer @@ -86,7 +87,10 @@ void* SkCachingPixelRef::onLockPixels(SkColorTable** colorTable) { // bitmap (SkScaledImageCache::Rec.fBitmap) that holds a // reference to the concrete PixelRef while this record is // locked. - return pixels; + rec->fPixels = pixels; + rec->fColorTable = NULL; + rec->fRowBytes = bitmap.rowBytes(); + return true; } void SkCachingPixelRef::onUnlockPixels() { diff --git a/src/lazy/SkCachingPixelRef.h b/src/lazy/SkCachingPixelRef.h index 4a0387ddf..75710d8bd 100644 --- a/src/lazy/SkCachingPixelRef.h +++ b/src/lazy/SkCachingPixelRef.h @@ -40,7 +40,7 @@ public: protected: virtual ~SkCachingPixelRef(); - virtual void* onLockPixels(SkColorTable** colorTable) SK_OVERRIDE; + virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE; virtual void onUnlockPixels() SK_OVERRIDE; virtual bool onLockPixelsAreWritable() const SK_OVERRIDE { return false; } @@ -58,12 +58,12 @@ private: SkImageGenerator* const fImageGenerator; bool fErrorInDecoding; void* fScaledCacheId; - const SkImageInfo fInfo; const size_t fRowBytes; SkCachingPixelRef(SkImageGenerator* imageGenerator, const SkImageInfo& info, size_t rowBytes); + typedef SkPixelRef INHERITED; }; diff --git a/src/lazy/SkDiscardablePixelRef.cpp b/src/lazy/SkDiscardablePixelRef.cpp index e614db37e..e9e2d8a3e 100644 --- a/src/lazy/SkDiscardablePixelRef.cpp +++ b/src/lazy/SkDiscardablePixelRef.cpp @@ -10,17 +10,15 @@ SkDiscardablePixelRef::SkDiscardablePixelRef(SkImageGenerator* generator, const SkImageInfo& info, - size_t size, size_t rowBytes, SkDiscardableMemory::Factory* fact) - : fGenerator(generator) + : INHERITED(info) + , fGenerator(generator) , fDMFactory(fact) - , fInfo(info) - , fSize(size) , fRowBytes(rowBytes) - , fDiscardableMemory(NULL) { + , fDiscardableMemory(NULL) +{ SkASSERT(fGenerator != NULL); - SkASSERT(fSize > 0); SkASSERT(fRowBytes > 0); // The SkImageGenerator contract requires fGenerator to always // decode the same image on each call to getPixels(). @@ -34,28 +32,39 @@ SkDiscardablePixelRef::~SkDiscardablePixelRef() { SkDELETE(fGenerator); } -void* SkDiscardablePixelRef::onLockPixels(SkColorTable**) { +bool SkDiscardablePixelRef::onNewLockPixels(LockRec* rec) { if (fDiscardableMemory != NULL) { if (fDiscardableMemory->lock()) { - return fDiscardableMemory->data(); + rec->fPixels = fDiscardableMemory->data(); + rec->fColorTable = NULL; + rec->fRowBytes = fRowBytes; + return true; } SkDELETE(fDiscardableMemory); fDiscardableMemory = NULL; } + + const size_t size = this->info().getSafeSize(fRowBytes); if (fDMFactory != NULL) { - fDiscardableMemory = fDMFactory->create(fSize); + fDiscardableMemory = fDMFactory->create(size); } else { - fDiscardableMemory = SkDiscardableMemory::Create(fSize); + fDiscardableMemory = SkDiscardableMemory::Create(size); } if (NULL == fDiscardableMemory) { - return NULL; // Memory allocation failed. + return false; // Memory allocation failed. } + void* pixels = fDiscardableMemory->data(); - if (!fGenerator->getPixels(fInfo, pixels, fRowBytes)) { - return NULL; // TODO(halcanary) Find out correct thing to do. + if (!fGenerator->getPixels(this->info(), pixels, fRowBytes)) { + return false; // TODO(halcanary) Find out correct thing to do. } - return pixels; + + rec->fPixels = pixels; + rec->fColorTable = NULL; + rec->fRowBytes = fRowBytes; + return true; } + void SkDiscardablePixelRef::onUnlockPixels() { if (fDiscardableMemory != NULL) { fDiscardableMemory->unlock(); @@ -76,7 +85,6 @@ bool SkDiscardablePixelRef::Install(SkImageGenerator* generator, } SkAutoTUnref ref(SkNEW_ARGS(SkDiscardablePixelRef, (generator, info, - dst->getSize(), dst->rowBytes(), factory))); dst->setPixelRef(ref); diff --git a/src/lazy/SkDiscardablePixelRef.h b/src/lazy/SkDiscardablePixelRef.h index 78dcd6679..313660efc 100644 --- a/src/lazy/SkDiscardablePixelRef.h +++ b/src/lazy/SkDiscardablePixelRef.h @@ -50,7 +50,8 @@ public: protected: ~SkDiscardablePixelRef(); - virtual void* onLockPixels(SkColorTable**) SK_OVERRIDE; + + virtual bool onNewLockPixels(LockRec*) SK_OVERRIDE; virtual void onUnlockPixels() SK_OVERRIDE; virtual bool onLockPixelsAreWritable() const SK_OVERRIDE { return false; } @@ -61,8 +62,6 @@ protected: private: SkImageGenerator* const fGenerator; SkDiscardableMemory::Factory* const fDMFactory; - const SkImageInfo fInfo; - const size_t fSize; // size of memory to be allocated const size_t fRowBytes; // These const members should not change over the life of the // PixelRef, since the SkBitmap doesn't expect them to change. @@ -72,8 +71,10 @@ private: /* Takes ownership of SkImageGenerator. */ SkDiscardablePixelRef(SkImageGenerator* generator, const SkImageInfo& info, - size_t size, size_t rowBytes, SkDiscardableMemory::Factory* factory); + + typedef SkPixelRef INHERITED; }; + #endif // SkDiscardablePixelRef_DEFINED diff --git a/tests/PictureTest.cpp b/tests/PictureTest.cpp index 9ef4bb06b..3c53dd383 100644 --- a/tests/PictureTest.cpp +++ b/tests/PictureTest.cpp @@ -9,6 +9,7 @@ #include "SkCanvas.h" #include "SkColorPriv.h" #include "SkData.h" +#include "SkDecodingImageGenerator.h" #include "SkError.h" #include "SkPaint.h" #include "SkPicture.h" @@ -335,32 +336,6 @@ static void test_bad_bitmap() { } #endif -#include "SkData.h" -#include "SkImageRef_GlobalPool.h" -// Class to test SkPixelRef::onRefEncodedData, since there are currently no implementations in skia. -class SkDataImageRef : public SkImageRef_GlobalPool { - -public: - SkDataImageRef(SkMemoryStream* stream) - : SkImageRef_GlobalPool(stream, SkBitmap::kNo_Config) { - SkASSERT(stream != NULL); - fData = stream->copyToData(); - this->setImmutable(); - } - - ~SkDataImageRef() { - fData->unref(); - } - - virtual SkData* onRefEncodedData() SK_OVERRIDE { - fData->ref(); - return fData; - } - -private: - SkData* fData; -}; - #include "SkImageEncoder.h" static SkData* encode_bitmap_to_data(size_t* offset, const SkBitmap& bm) { @@ -402,14 +377,10 @@ static void test_bitmap_with_encoded_data(skiatest::Reporter* reporter) { return; } SkAutoDataUnref data(wStream.copyToData()); - SkMemoryStream memStream; - memStream.setData(data); - // Use the encoded bitmap as the data for an image ref. SkBitmap bm; - SkAutoTUnref imageRef(SkNEW_ARGS(SkDataImageRef, (&memStream))); - imageRef->getInfo(&bm); - bm.setPixelRef(imageRef); + bool installSuccess = SkDecodingImageGenerator::Install(data, &bm); + REPORTER_ASSERT(reporter, installSuccess); // Write both bitmaps to pictures, and ensure that the resulting data streams are the same. // Flattening original will follow the old path of performing an encode, while flattening bm diff --git a/tests/PixelRefTest.cpp b/tests/PixelRefTest.cpp index ce2575e83..f3625bd64 100644 --- a/tests/PixelRefTest.cpp +++ b/tests/PixelRefTest.cpp @@ -17,33 +17,35 @@ private: } // namespace DEF_TEST(PixelRef_GenIDChange, r) { - SkMallocPixelRef pixelRef(NULL, 0, NULL); // We don't really care about the pixels here. + SkImageInfo info = { 10, 10, kPMColor_SkColorType, kPremul_SkAlphaType }; + + SkAutoTUnref pixelRef(SkMallocPixelRef::NewAllocate(info, 0, NULL)); // Register a listener. int count = 0; - pixelRef.addGenIDChangeListener(SkNEW_ARGS(TestListener, (&count))); + pixelRef->addGenIDChangeListener(SkNEW_ARGS(TestListener, (&count))); REPORTER_ASSERT(r, 0 == count); // No one has looked at our pixelRef's generation ID, so invalidating it doesn't make sense. // (An SkPixelRef tree falls in the forest but there's nobody around to hear it. Do we care?) - pixelRef.notifyPixelsChanged(); + pixelRef->notifyPixelsChanged(); REPORTER_ASSERT(r, 0 == count); // Force the generation ID to be calculated. - REPORTER_ASSERT(r, 0 != pixelRef.getGenerationID()); + REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID()); // Our listener was dropped in the first call to notifyPixelsChanged(). This is a no-op. - pixelRef.notifyPixelsChanged(); + pixelRef->notifyPixelsChanged(); REPORTER_ASSERT(r, 0 == count); // Force the generation ID to be recalculated, then add a listener. - REPORTER_ASSERT(r, 0 != pixelRef.getGenerationID()); - pixelRef.addGenIDChangeListener(SkNEW_ARGS(TestListener, (&count))); - pixelRef.notifyPixelsChanged(); + REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID()); + pixelRef->addGenIDChangeListener(SkNEW_ARGS(TestListener, (&count))); + pixelRef->notifyPixelsChanged(); REPORTER_ASSERT(r, 1 == count); // Quick check that NULL is safe. - REPORTER_ASSERT(r, 0 != pixelRef.getGenerationID()); - pixelRef.addGenIDChangeListener(NULL); - pixelRef.notifyPixelsChanged(); + REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID()); + pixelRef->addGenIDChangeListener(NULL); + pixelRef->notifyPixelsChanged(); } diff --git a/tests/SerializationTest.cpp b/tests/SerializationTest.cpp index 7ae06d737..f1d0f900f 100644 --- a/tests/SerializationTest.cpp +++ b/tests/SerializationTest.cpp @@ -148,6 +148,7 @@ static T* TestFlattenableSerialization(T* testObj, bool shouldSucceed, REPORTER_ASSERT(reporter, SkAlign4(bytesWritten) == bytesWritten); unsigned char dataWritten[1024]; + SkASSERT(bytesWritten <= sizeof(dataWritten)); writer.writeToMemory(dataWritten); // Make sure this fails when it should (test with smaller size, but still multiple of 4) @@ -307,10 +308,22 @@ static void Tests(skiatest::Reporter* reporter) { TestBitmapSerialization(validBitmap, invalidBitmap, true, reporter); // Create a bitmap with a pixel ref too small + SkImageInfo info; + info.fWidth = 256; + info.fHeight = 256; + info.fColorType = kPMColor_SkColorType; + info.fAlphaType = kPremul_SkAlphaType; + SkBitmap invalidBitmap2; - invalidBitmap2.setConfig(SkBitmap::kARGB_8888_Config, 256, 256); - invalidBitmap2.setPixelRef(SkNEW_ARGS(SkMallocPixelRef, - (NULL, 256, NULL)))->unref(); + invalidBitmap2.setConfig(info); + + // Hack to force invalid, by making the pixelref smaller than its + // owning bitmap. + info.fWidth = 32; + info.fHeight = 1; + + invalidBitmap2.setPixelRef(SkMallocPixelRef::NewAllocate( + info, invalidBitmap2.rowBytes(), NULL))->unref(); // The deserialization should detect the pixel ref being too small and fail TestBitmapSerialization(validBitmap, invalidBitmap2, false, reporter);