/* * Copyright 2012 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifdef SK_DEBUG #include "SkBitmap.h" #include "SkBitmapFactory.h" #include "SkCanvas.h" #include "SkColor.h" #include "SkData.h" #include "SkImageDecoder.h" #include "SkImageEncoder.h" #include "SkLazyPixelRef.h" #include "SkLruImageCache.h" #include "SkPaint.h" #include "SkPurgeableImageCache.h" #include "SkStream.h" #include "SkTemplates.h" #include "Test.h" static SkBitmap* create_bitmap() { SkBitmap* bm = SkNEW(SkBitmap); // Use a large bitmap. const int W = 1000, H = 1000; bm->setConfig(SkBitmap::kARGB_8888_Config, W, H); bm->allocPixels(); bm->eraseColor(SK_ColorBLACK); SkCanvas canvas(*bm); SkPaint paint; paint.setColor(SK_ColorBLUE); canvas.drawRectCoords(0, 0, SkIntToScalar(W/2), SkIntToScalar(H/2), paint); return bm; } static SkData* create_data_from_bitmap(const SkBitmap& bm) { SkDynamicMemoryWStream stream; if (SkImageEncoder::EncodeStream(&stream, bm, SkImageEncoder::kPNG_Type, 100)) { return stream.copyToData(); } return NULL; } static void assert_bounds_equal(skiatest::Reporter* reporter, const SkBitmap& bm1, const SkBitmap& bm2) { REPORTER_ASSERT(reporter, bm1.width() == bm2.width()); REPORTER_ASSERT(reporter, bm1.height() == bm2.height()); } static void test_cache(skiatest::Reporter* reporter, SkImageCache* cache) { // Test the cache directly: cache->purgeAllUnpinnedCaches(); intptr_t ID = SkImageCache::UNINITIALIZED_ID; const size_t size = 1000; char buffer[size]; sk_bzero((void*) buffer, size); void* memory = cache->allocAndPinCache(size, &ID); if (memory != NULL) { memcpy(memory, (void*)buffer, size); REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) == SkImageCache::kPinned_MemoryStatus); cache->releaseCache(ID); REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) != SkImageCache::kPinned_MemoryStatus); SkImageCache::DataStatus dataStatus; memory = cache->pinCache(ID, &dataStatus); if (memory != NULL) { REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) == SkImageCache::kPinned_MemoryStatus); if (SkImageCache::kRetained_DataStatus == dataStatus) { REPORTER_ASSERT(reporter, !memcmp(memory, (void*) buffer, size)); } cache->releaseCache(ID); REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) != SkImageCache::kPinned_MemoryStatus); cache->purgeAllUnpinnedCaches(); REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) != SkImageCache::kPinned_MemoryStatus); memory = cache->pinCache(ID, &dataStatus); if (memory != NULL) { // The memory block may or may not have survived the purging (at the // memory manager's whim) so we cannot check dataStatus here. cache->releaseCache(ID); REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) != SkImageCache::kPinned_MemoryStatus); cache->throwAwayCache(ID); REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) == SkImageCache::kFreed_MemoryStatus); } else { REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) == SkImageCache::kFreed_MemoryStatus); } } } } static void test_factory(skiatest::Reporter* reporter, SkImageCache* cache, SkData* encodedData, const SkBitmap& origBitmap) { SkBitmapFactory factory(&SkImageDecoder::DecodeMemoryToTarget); factory.setImageCache(cache); SkAutoTDelete bitmapFromFactory(SkNEW(SkBitmap)); bool success = factory.installPixelRef(encodedData, bitmapFromFactory.get()); // This assumes that if the encoder worked, the decoder should also work, so the above call // should not fail. REPORTER_ASSERT(reporter, success); assert_bounds_equal(reporter, origBitmap, *bitmapFromFactory.get()); SkPixelRef* pixelRef = bitmapFromFactory->pixelRef(); REPORTER_ASSERT(reporter, pixelRef != NULL); if (NULL == cache) { // This assumes that installPixelRef called lockPixels. REPORTER_ASSERT(reporter, bitmapFromFactory->readyToDraw()); } else { // Lazy decoding REPORTER_ASSERT(reporter, !bitmapFromFactory->readyToDraw()); SkLazyPixelRef* lazyRef = static_cast(pixelRef); intptr_t cacheID = lazyRef->getCacheId(); REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) != SkImageCache::kPinned_MemoryStatus); { SkAutoLockPixels alp(*bitmapFromFactory.get()); REPORTER_ASSERT(reporter, bitmapFromFactory->readyToDraw()); cacheID = lazyRef->getCacheId(); REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) == SkImageCache::kPinned_MemoryStatus); } REPORTER_ASSERT(reporter, !bitmapFromFactory->readyToDraw()); REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) != SkImageCache::kPinned_MemoryStatus); bitmapFromFactory.free(); REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) == SkImageCache::kFreed_MemoryStatus); } } class ImageCacheHolder : public SkNoncopyable { public: ~ImageCacheHolder() { fCaches.safeUnrefAll(); } void addImageCache(SkImageCache* cache) { SkSafeRef(cache); *fCaches.append() = cache; } int count() const { return fCaches.count(); } SkImageCache* getAt(int i) { if (i < 0 || i > fCaches.count()) { return NULL; } return fCaches.getAt(i); } private: SkTDArray fCaches; }; static void TestBitmapFactory(skiatest::Reporter* reporter) { SkAutoTDelete bitmap(create_bitmap()); SkASSERT(bitmap.get() != NULL); SkAutoDataUnref encodedBitmap(create_data_from_bitmap(*bitmap.get())); bool encodeSucceeded = encodedBitmap.get() != NULL; SkASSERT(encodeSucceeded); ImageCacheHolder cacheHolder; SkAutoTUnref lruCache(SkNEW_ARGS(SkLruImageCache, (1024 * 1024))); cacheHolder.addImageCache(lruCache); cacheHolder.addImageCache(NULL); SkImageCache* purgeableCache = SkPurgeableImageCache::Create(); if (purgeableCache != NULL) { cacheHolder.addImageCache(purgeableCache); purgeableCache->unref(); } for (int i = 0; i < cacheHolder.count(); i++) { SkImageCache* cache = cacheHolder.getAt(i); if (cache != NULL) { test_cache(reporter, cache); } if (encodeSucceeded) { test_factory(reporter, cache, encodedBitmap, *bitmap.get()); } } } #include "TestClassDef.h" DEFINE_TESTCLASS("BitmapFactory", TestBitmapFactoryClass, TestBitmapFactory) #endif // SK_DEBUG