blob: c0d5d9055b7d91d8b8195f76d18e194ec0074c07 [file] [log] [blame]
/*
* Copyright 2012 Google Inc.
*
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#include "Sk64.h"
#include "SkLazyPixelRef.h"
#include "SkColorTable.h"
#include "SkData.h"
#include "SkImageCache.h"
#include "SkImagePriv.h"
SkLazyPixelRef::SkLazyPixelRef(SkData* data, SkBitmapFactory::DecodeProc proc, SkImageCache* cache)
// Pass NULL for the Mutex so that the default (ring buffer) will be used.
: INHERITED(NULL)
, fDecodeProc(proc)
, fImageCache(cache)
, fCacheId(SkImageCache::UNINITIALIZED_ID) {
SkASSERT(fDecodeProc != NULL);
if (NULL == data) {
fData = SkData::NewEmpty();
fErrorInDecoding = true;
} else {
fData = data;
fData->ref();
fErrorInDecoding = data->size() == 0;
}
SkASSERT(cache != NULL);
cache->ref();
// Since this pixel ref bases its data on encoded data, it should never change.
this->setImmutable();
}
SkLazyPixelRef::~SkLazyPixelRef() {
SkASSERT(fData != NULL);
fData->unref();
SkASSERT(fImageCache);
if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
fImageCache->throwAwayCache(fCacheId);
}
fImageCache->unref();
}
static size_t ComputeMinRowBytesAndSize(const SkImage::Info& info, size_t* rowBytes) {
*rowBytes = SkImageMinRowBytes(info);
Sk64 safeSize;
safeSize.setZero();
if (info.fHeight > 0) {
safeSize.setMul(info.fHeight, *rowBytes);
}
SkASSERT(!safeSize.isNeg());
return safeSize.is32() ? safeSize.get32() : 0;
}
void* SkLazyPixelRef::onLockPixels(SkColorTable**) {
if (fErrorInDecoding) {
return NULL;
}
SkBitmapFactory::Target target;
// Check to see if the pixels still exist in the cache.
target.fAddr = SkImageCache::UNINITIALIZED_ID == fCacheId ?
NULL : fImageCache->pinCache(fCacheId);
if (NULL == target.fAddr) {
SkImage::Info info;
SkASSERT(fData != NULL && fData->size() > 0);
// FIXME: As an optimization, only do this part once.
fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, NULL);
if (fErrorInDecoding) {
fCacheId = SkImageCache::UNINITIALIZED_ID;
return NULL;
}
// Allocate the memory.
size_t bytes = ComputeMinRowBytesAndSize(info, &target.fRowBytes);
target.fAddr = fImageCache->allocAndPinCache(bytes, &fCacheId);
if (NULL == target.fAddr) {
// Space could not be allocated.
fCacheId = SkImageCache::UNINITIALIZED_ID;
return NULL;
}
SkASSERT(SkImageCache::UNINITIALIZED_ID != fCacheId);
fErrorInDecoding = !fDecodeProc(fData->data(), fData->size(), &info, &target);
if (fErrorInDecoding) {
fImageCache->throwAwayCache(fCacheId);
fCacheId = SkImageCache::UNINITIALIZED_ID;
return NULL;
}
}
return target.fAddr;
}
void SkLazyPixelRef::onUnlockPixels() {
if (fErrorInDecoding) {
return;
}
if (fCacheId != SkImageCache::UNINITIALIZED_ID) {
fImageCache->releaseCache(fCacheId);
}
}
SkData* SkLazyPixelRef::onRefEncodedData() {
fData->ref();
return fData;
}