| /* | 
 |  * 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<SkBitmap> 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<SkLazyPixelRef*>(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<SkImageCache*> fCaches; | 
 | }; | 
 |  | 
 | static void TestBitmapFactory(skiatest::Reporter* reporter) { | 
 |     SkAutoTDelete<SkBitmap> 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<SkLruImageCache> 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 |