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.
*/
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;
};
// 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
#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
/**
/** 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
*/
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
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 */
// 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;
class GrTexture;
class GrRenderTarget;
+struct SkImageInfo;
class GrSurface : public GrResource {
public:
*/
const GrTextureDesc& desc() const { return fDesc; }
+ void asImageInfo(SkImageInfo*) const;
+
/**
* @return the texture associated with the surface, may be NULL.
*/
* 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);
*/
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;
* 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();
@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();
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;
SkImageDecoderFactory* fFactory; // may be null
SkStreamRewindable* fStream;
- SkBitmap::Config fConfig;
int fSampleSize;
bool fDoDither;
bool fErrorInDecoding;
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();
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();
}
}
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();)
*/
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;
, 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() {
#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;
}
} 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;
-
/*
* 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() {
}
}
-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);
}
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);
}
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;
}
// 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();
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
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
}
}
-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() {
SkASSERT(fLockCount > 0);
if (0 == --fLockCount) {
this->onUnlockPixels();
- fPixels = NULL;
- fColorTable = NULL;
+ fRec.zero();
}
}
}
///////////////////////////////////////////////////////////////////////////////
+#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();
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) {
}
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;
#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());
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();
}
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;
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) {
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",
}
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;
}
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;
+}
// 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() {
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;
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.
#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() {
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);
}
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;
virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
private:
- SkData* fData;
+ SkData* fData;
+ size_t fRB;
typedef SkPixelRef INHERITED;
};
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();
}
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()));
}
//#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;
#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();
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)) {
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;
}
}
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 {
SkImageRef::SkImageRef(SkFlattenableReadBuffer& buffer, SkBaseMutex* mutex)
: INHERITED(buffer, mutex), fErrorInDecoding(false) {
- fConfig = (SkBitmap::Config)buffer.readUInt();
fSampleSize = buffer.readInt();
fDoDither = buffer.readBool();
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.
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);
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;
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)
#include "SkCachingPixelRef.h"
#include "SkScaledImageCache.h"
-
bool SkCachingPixelRef::Install(SkImageGenerator* generator,
SkBitmap* dst) {
SkImageInfo info;
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);
}
// 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);
}
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
// 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() {
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; }
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;
};
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().
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();
}
SkAutoTUnref<SkDiscardablePixelRef> ref(SkNEW_ARGS(SkDiscardablePixelRef,
(generator, info,
- dst->getSize(),
dst->rowBytes(),
factory)));
dst->setPixelRef(ref);
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; }
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.
/* 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
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkData.h"
+#include "SkDecodingImageGenerator.h"
#include "SkError.h"
#include "SkPaint.h"
#include "SkPicture.h"
}
#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) {
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
} // 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);
}
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)
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);