remvoe duplicate impl for SkImageInfo flattening
authorreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 11 Dec 2013 18:38:46 +0000 (18:38 +0000)
committerreed@google.com <reed@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Wed, 11 Dec 2013 18:38:46 +0000 (18:38 +0000)
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 eabd6b2ed4e494b323c08f32358f45950a0368c3.

BUG=

Review URL: https://codereview.chromium.org/108773003

git-svn-id: http://skia.googlecode.com/svn/trunk@12624 2bbb7eff-a529-9590-31e7-b0007b416f81

36 files changed:
include/core/SkBitmapDevice.h
include/core/SkMallocPixelRef.h
include/core/SkPicture.h
include/core/SkPixelRef.h
include/gpu/GrSurface.h
include/gpu/SkGr.h
include/gpu/SkGrPixelRef.h
include/images/SkImageRef.h
include/images/SkImageRef_GlobalPool.h
samplecode/SamplePicture.cpp
src/core/SkBitmap.cpp
src/core/SkBitmapDevice.cpp
src/core/SkImageFilterUtils.cpp
src/core/SkMallocPixelRef.cpp
src/core/SkMaskFilter.cpp
src/core/SkPixelRef.cpp
src/effects/gradients/SkGradientShader.cpp
src/gpu/GrSurface.cpp
src/gpu/SkGpuDevice.cpp
src/gpu/SkGr.cpp
src/gpu/SkGrPixelRef.cpp
src/image/SkDataPixelRef.cpp
src/image/SkDataPixelRef.h
src/image/SkImage_Raster.cpp
src/image/SkSurface_Raster.cpp
src/images/SkImageRef.cpp
src/images/SkImageRef_GlobalPool.cpp
src/images/SkImageRef_ashmem.cpp
src/images/SkImageRef_ashmem.h
src/lazy/SkCachingPixelRef.cpp
src/lazy/SkCachingPixelRef.h
src/lazy/SkDiscardablePixelRef.cpp
src/lazy/SkDiscardablePixelRef.h
tests/PictureTest.cpp
tests/PixelRefTest.cpp
tests/SerializationTest.cpp

index 83f480c60c21baf5e883abcac98f1f45977df071..f3d40d0ce8d9ca53102fb360b0b76e5cd799e59c 100644 (file)
@@ -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.
index 100a15d90abb4ca55b30aa9af47e5ce17f18fa67..5ef70d69bc8ea020c8f0cc902e02760e5ea44c85 100644 (file)
 */
 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();
-
-    SkMallocPixelRef(SkFlattenableReadBuffer& buffer);
+    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;
 
-    // Returns the allocation size for the pixels
-    virtual size_t getAllocatedSizeInBytes() const SK_OVERRIDE { return fSize; }
+    SkMallocPixelRef(SkFlattenableReadBuffer& buffer);
+    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;
 };
index bce343ec040d28bdaef60f4c8cd1b8d9e0ce8d7b..cd6b3bcbb1515ffadc62aa5dbf199d8b9cb5b6ee 100644 (file)
@@ -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
index b87b0dc114b34958ff36f93ea3d464320334ae60..472599eeb3191c1da4a6f252ed98029e5583ef12 100644 (file)
 #include "SkRefCnt.h"
 #include "SkString.h"
 #include "SkFlattenable.h"
+#include "SkImageInfo.h"
 #include "SkTDArray.h"
 
-#define SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR
+//#define SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR
+
+#define SK_SUPPORT_LEGACY_ONLOCKPIXELS
 
 #ifdef SK_DEBUG
     /**
@@ -67,12 +70,24 @@ public:
     /** 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
      */
@@ -80,10 +95,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
@@ -240,14 +264,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 */
@@ -291,14 +329,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
     SkImageInfo     fInfo;
-
-    void*           fPixels;
-    SkColorTable*   fColorTable;    // we do not track ownership, subclass does
+    
+    // LockRec is only valid if we're in a locked state (isLocked())
+    LockRec         fRec;
     int             fLockCount;
 
     mutable uint32_t fGenerationID;
index c401a905ff2177ca2ffd523c28f78639d8cc2ef7..15e44ab593675acc7f03db4dd214b867c9ec0153 100644 (file)
@@ -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.
      */
index 5e5ca4b72c30f898bb9c07d829f3824f8ef652be..db08548f5d544a66e39d5de3c97c5fd9155643ee 100644 (file)
@@ -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);
index c29c27fb3bdc0b3d0963fcaa0fda82ef3d0285a1..4d33b9d06b01498e9891db2e3dd2b43bd414016b 100644 (file)
  */
 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,6 @@ public:
      * cache and would like the pixel ref to unlock it in its destructor then transferCacheLock
      * should be set to true.
      */
-    SkGrPixelRef(GrSurface*, bool transferCacheLock = false);
     SkGrPixelRef(const SkImageInfo&, GrSurface*, bool transferCacheLock = false);
     virtual ~SkGrPixelRef();
 
index 0599a8d9633dfe8a7284801b49b5d3efc78a8b9b..36f95e64b2410f1fe2909ff015f3b3d2ff572cc9 100644 (file)
@@ -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;
index 3adc0f61503ef2ac22360e3dce582e26f0e75612..caaf2487de7ec51c1494d4e7fccae2d008e75862 100644 (file)
@@ -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();
 
index 66289affe0992219b6466051e622061aff94ce64..2f7d691d17af7b18aa64d556e59ffd9560b3982e 100644 (file)
@@ -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();
         }
     }
index 25a6b1dba44790ce0bee01bb22f4b92bfd54c426..7a7f690b2a5159ac1c09ff744adf62a36ba6df6e 100644 (file)
@@ -453,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();)
@@ -521,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;
     }
-
-    void* addr = sk_malloc_flags(size.get32(), 0);  // returns NULL on failure
-    if (NULL == addr) {
+    
+    SkPixelRef* pr = SkMallocPixelRef::NewAllocate(info, dst->rowBytes(),
+                                                   ctable);
+    if (NULL == pr) {
         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;
index 1668618cf740bac454bd7af06774e5994d4443af..368c8075112e6129b1e72c78d151536d76c68eef 100644 (file)
@@ -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() {
index 8385fb446ae0726ade2ccfbad3250239e6209211..e535d934f8cd65991c6c085946ac860fb877d03c 100644 (file)
 #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;
index f229e9de34d0fa8dbdd29304dd0ac0f7a78e5611..613491a3aabc9079a2d599b715206871f83cc153 100644 (file)
-
 /*
  * 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;
+    }
+    
+    // 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;
+}
+
+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 (kIndex_8_SkColorType != info.fColorType) {
+        ctable = NULL;
+    }
+
     fStorage = storage;
-    fSize = size;
     fCTable = ctable;
+    fRB = rowBytes;
     SkSafeRef(ctable);
-    fOwnPixels = ownPixels;
-
-    this->setPreLocked(fStorage, fCTable);
+    
+    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);
 }
index f062f135fdbebbd4f5016bfde05dc0a424e04ccb..adfed4109899dfda776e8b765fa393d02f8309ae 100644 (file)
@@ -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;
 }
 
index b5daf0b57a90ca0321babf11c37da2eef05fab93..60b5cfb26c6960e7de3c5d49b38cb95de620e15a 100644 (file)
@@ -82,44 +82,32 @@ 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(const SkImageInfo&, SkBaseMutex* mutex) {
-    this->setMutex(mutex);
-    fPixels = NULL;
-    fColorTable = NULL; // we do not track ownership of this
-    fLockCount = 0;
-    this->needsNewGenID();
-    fIsImmutable = false;
-    fPreLocked = false;
-}
-
-SkPixelRef::SkPixelRef(const SkImageInfo&) {
+SkPixelRef::SkPixelRef(const SkImageInfo& info) {
     this->setMutex(NULL);
-    fPixels = NULL;
-    fColorTable = NULL; // we do not track ownership of this
+    fInfo = info;
+    fRec.zero();
     fLockCount = 0;
     this->needsNewGenID();
     fIsImmutable = false;
     fPreLocked = false;
 }
 
-#ifdef SK_SUPPORT_LEGACY_PIXELREF_CONSTRUCTOR
-// THIS GUY IS DEPRECATED -- don't use me!
-SkPixelRef::SkPixelRef(SkBaseMutex* mutex) {
+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;
     fPreLocked = false;
 }
-#endif
 
 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();
@@ -143,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
@@ -156,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
@@ -170,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() {
@@ -191,8 +193,7 @@ void SkPixelRef::unlockPixels() {
         SkASSERT(fLockCount > 0);
         if (0 == --fLockCount) {
             this->onUnlockPixels();
-            fPixels = NULL;
-            fColorTable = NULL;
+            fRec.zero();
         }
     }
 }
@@ -273,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();
index 27761993461ba7761a8afc57c36eac9ec2754cc4..5d200d18d354135f7f11e4807964631edc32409e 100644 (file)
@@ -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;
index fed95f232fe4b18d34ef4f6d7844346aacc44eba..1fcc4ff18be23eeb51dc843489a32c00dfbbf685 100644 (file)
@@ -8,9 +8,19 @@
 #include "GrSurface.h"
 
 #include "SkBitmap.h"
+#include "SkGr.h"
 #include "SkImageEncoder.h"
 #include <stdio.h>
 
+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());
index ce02f2c55fc97fa76beba1068cc36ae9277b44c6..a413d0420465247250ba4ce8bac057f89ef4f0f0 100644 (file)
@@ -214,7 +214,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();
 }
@@ -224,8 +227,8 @@ SkGpuDevice::SkGpuDevice(GrContext* context,
                          int width,
                          int height,
                          int sampleCount)
-    : SkBitmapDevice(make_bitmap(config, width, height, false /*isOpaque*/)) {
-
+    : SkBitmapDevice(make_bitmap(config, width, height, false /*isOpaque*/))
+{
     fDrawProcs = NULL;
 
     fContext = context;
@@ -245,6 +248,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<GrTexture> texture(fContext->createUncachedTexture(desc, NULL, 0));
 
     if (NULL != texture) {
@@ -254,7 +265,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",
@@ -840,11 +851,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;
 }
 
index c7ae0c8f36684f398043329a4b75e2f0b1bf9e72..a3f0eefa91f85a54b99565014f08ce92c799c2d4 100644 (file)
@@ -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 = kIndex_8_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;
+}
index 012942667c72b8c134ef8333b2deb708cd11c8ee..74b1a4faa24c7fb8d74b8294ef560a1e0ad01bfe 100644 (file)
 // 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,31 +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) {
-    // 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.
-    // If the GrTexture exists take a ref to that (rather than the render
-    // target)
-    fSurface = surface->asTexture();
-#else
-    fSurface = NULL;
-#endif
-    if (NULL == fSurface) {
-        fSurface = surface;
-    }
-    fUnlock = transferCacheLock;
-    SkSafeRef(surface);
-}
-
-SkGrPixelRef::SkGrPixelRef(const SkImageInfo&, 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.
index 7897bf93158437efa69abe1e8ea8a5baf5516ced..875f933b9c1f6faa530cba41103bc8b632b4492f 100644 (file)
@@ -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<void*>(fData->data()), NULL);
+    this->setPreLocked(const_cast<void*>(fData->data()), rowBytes, NULL);
 }
 
 SkDataPixelRef::~SkDataPixelRef() {
     fData->unref();
 }
 
-void* SkDataPixelRef::onLockPixels(SkColorTable** ct) {
-    *ct = NULL;
-    return const_cast<void*>(fData->data());
+bool SkDataPixelRef::onNewLockPixels(LockRec* rec) {
+    rec->fPixels = const_cast<void*>(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<void*>(fData->data()), NULL);
+    fRB = buffer.read32();
+    this->setPreLocked(const_cast<void*>(fData->data()), fRB, NULL);
 }
index 50c885714b91f1c3b3c389b441363a2d499ca707..c2e52cd9e12ccb02b5bea2bf92a674927c7926c1 100644 (file)
@@ -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;
 };
index a872ae36e52d3aad65b23fffa280544876b252d5..93de5ea3abb1765cd03d26a2855e93bac20e67dd 100644 (file)
@@ -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();
 }
 
index 27db504df6f056e8d35d1ca68adc608bfa4164d7..61ade6f46c8ec6584c3a5a18995dff3a766cca2c 100644 (file)
@@ -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) {
-        return NULL;
-    }
-
-    size_t size = (size_t)size64;
-    void* pixels = sk_malloc_throw(size);
-    if (NULL == pixels) {
+    SkAutoTUnref<SkPixelRef> pr(SkMallocPixelRef::NewAllocate(info, 0, NULL));
+    if (NULL == pr.get()) {
         return NULL;
     }
-
-    SkAutoTUnref<SkPixelRef> 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()));
 }
index 1a8284bdd4a6e730da950ce244355867295cb0de..99782c45c08bf5faaa91006e34f489bbb0438f38 100644 (file)
 
 //#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.
index 352dd42d9f79a3c94dabafff20edbeeb7fdb8b99..f91cebabbf8e7e0c26f06533e35122bc12b62039 100644 (file)
@@ -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);
index 0dba1d119140d4d89615e72926994c6a6a7afb1c..383a487d2be60c25fd42f428db93f39ab11ea8f8 100644 (file)
@@ -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;
index efee5e759b95ad9bd75483ba94beac4f1fcdec1b..a2652fbc300f197924b36c4cf831f32221e20700 100644 (file)
@@ -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)
index 667a94931b1a33fe59b14d53f9990eb084fe8214..fba98455639e0b1e59fafe9c271a2d60fa5883f0 100644 (file)
@@ -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() {
index 4a0387ddf8e1b827f836c6ee49f6c7c860ac2d7b..75710d8bde4c76eb5478ae8fcd8b905946c2fdce 100644 (file)
@@ -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;
 };
 
index 6a9507c8c76a713bba3c7a85388e3f8e4c78d702..eb35d0fcc4d5cf4c3cc9eed26a0415183afea76b 100644 (file)
 
 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().
@@ -35,28 +33,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();
@@ -81,7 +90,6 @@ bool SkInstallDiscardablePixelRef(SkImageGenerator* generator,
     }
     SkAutoTUnref<SkDiscardablePixelRef> ref(SkNEW_ARGS(SkDiscardablePixelRef,
                                                    (generator, info,
-                                                    dst->getSize(),
                                                     dst->rowBytes(),
                                                     factory)));
     dst->setPixelRef(ref);
index 44c6df9637ab2db5dc503d9e872095c29a09ad02..0a727b6367eb80172324cf9d4aed72f60b7c07d2 100644 (file)
@@ -19,7 +19,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; }
 
@@ -30,8 +31,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.
@@ -41,12 +40,14 @@ private:
     /* Takes ownership of SkImageGenerator. */
     SkDiscardablePixelRef(SkImageGenerator* generator,
                           const SkImageInfo& info,
-                          size_t size,
                           size_t rowBytes,
                           SkDiscardableMemory::Factory* factory);
+
     friend bool SkInstallDiscardablePixelRef(SkImageGenerator*,
                                              SkBitmap*,
                                              SkDiscardableMemory::Factory*);
+
     typedef SkPixelRef INHERITED;
 };
+
 #endif  // SkDiscardablePixelRef_DEFINED
index 9ef4bb06bdba2551195a1051e6c47bab19220edf..3c53dd38381718db159b24c8fff0f639bee14c16 100644 (file)
@@ -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<SkDataImageRef> 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
index 470221c0fea0c44196751c9fcfc96e94fea81d44..e0ffd7a6017537fa78b1f3f03a4bd519f3b8c7ec 100644 (file)
@@ -51,35 +51,37 @@ 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<SkPixelRef> 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();
 
     test_info(r);
 }
index 7ae06d737e4f7643aa7e56abe06a01850ca8eb14..f1d0f900fd0eca09f187017b1b246e251f651635 100644 (file)
@@ -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);