michael@0: /* michael@0: * Copyright 2013 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "SkCachingPixelRef.h" michael@0: #include "SkScaledImageCache.h" michael@0: michael@0: bool SkCachingPixelRef::Install(SkImageGenerator* generator, michael@0: SkBitmap* dst) { michael@0: SkImageInfo info; michael@0: SkASSERT(dst != NULL); michael@0: if ((NULL == generator) michael@0: || !(generator->getInfo(&info)) michael@0: || !dst->setConfig(info, 0)) { michael@0: SkDELETE(generator); michael@0: return false; michael@0: } michael@0: SkAutoTUnref ref(SkNEW_ARGS(SkCachingPixelRef, michael@0: (info, generator, dst->rowBytes()))); michael@0: dst->setPixelRef(ref); michael@0: return true; michael@0: } michael@0: michael@0: SkCachingPixelRef::SkCachingPixelRef(const SkImageInfo& info, michael@0: SkImageGenerator* generator, michael@0: size_t rowBytes) michael@0: : INHERITED(info) michael@0: , fImageGenerator(generator) michael@0: , fErrorInDecoding(false) michael@0: , fScaledCacheId(NULL) michael@0: , fRowBytes(rowBytes) { michael@0: SkASSERT(fImageGenerator != NULL); michael@0: } michael@0: SkCachingPixelRef::~SkCachingPixelRef() { michael@0: SkDELETE(fImageGenerator); michael@0: SkASSERT(NULL == fScaledCacheId); michael@0: // Assert always unlock before unref. michael@0: } michael@0: michael@0: bool SkCachingPixelRef::onNewLockPixels(LockRec* rec) { michael@0: if (fErrorInDecoding) { michael@0: return false; // don't try again. michael@0: } michael@0: michael@0: const SkImageInfo& info = this->info(); michael@0: SkBitmap bitmap; michael@0: SkASSERT(NULL == fScaledCacheId); michael@0: fScaledCacheId = SkScaledImageCache::FindAndLock(this->getGenerationID(), michael@0: info.fWidth, michael@0: info.fHeight, michael@0: &bitmap); michael@0: if (NULL == fScaledCacheId) { michael@0: // Cache has been purged, must re-decode. michael@0: if ((!bitmap.setConfig(info, fRowBytes)) || !bitmap.allocPixels()) { michael@0: fErrorInDecoding = true; michael@0: return false; michael@0: } michael@0: SkAutoLockPixels autoLockPixels(bitmap); michael@0: if (!fImageGenerator->getPixels(info, bitmap.getPixels(), fRowBytes)) { michael@0: fErrorInDecoding = true; michael@0: return false; michael@0: } michael@0: fScaledCacheId = SkScaledImageCache::AddAndLock(this->getGenerationID(), michael@0: info.fWidth, michael@0: info.fHeight, michael@0: bitmap); michael@0: SkASSERT(fScaledCacheId != NULL); michael@0: } michael@0: michael@0: // Now bitmap should contain a concrete PixelRef of the decoded michael@0: // image. michael@0: SkAutoLockPixels autoLockPixels(bitmap); michael@0: void* pixels = bitmap.getPixels(); michael@0: SkASSERT(pixels != NULL); michael@0: michael@0: // At this point, the autoLockPixels will unlockPixels() michael@0: // to remove bitmap's lock on the pixels. We will then michael@0: // destroy bitmap. The *only* guarantee that this pointer michael@0: // remains valid is the guarantee made by michael@0: // SkScaledImageCache that it will not destroy the *other* michael@0: // bitmap (SkScaledImageCache::Rec.fBitmap) that holds a michael@0: // reference to the concrete PixelRef while this record is michael@0: // locked. michael@0: rec->fPixels = pixels; michael@0: rec->fColorTable = NULL; michael@0: rec->fRowBytes = bitmap.rowBytes(); michael@0: return true; michael@0: } michael@0: michael@0: void SkCachingPixelRef::onUnlockPixels() { michael@0: SkASSERT(fScaledCacheId != NULL); michael@0: SkScaledImageCache::Unlock( static_cast(fScaledCacheId)); michael@0: fScaledCacheId = NULL; michael@0: }