1/* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#ifdef SK_DEBUG 9 10#include "SkBitmap.h" 11#include "SkBitmapFactory.h" 12#include "SkCanvas.h" 13#include "SkColor.h" 14#include "SkData.h" 15#include "SkImageDecoder.h" 16#include "SkImageEncoder.h" 17#include "SkLazyPixelRef.h" 18#include "SkLruImageCache.h" 19#include "SkPaint.h" 20#include "SkPurgeableImageCache.h" 21#include "SkStream.h" 22#include "SkTemplates.h" 23#include "Test.h" 24 25static SkBitmap* create_bitmap() { 26 SkBitmap* bm = SkNEW(SkBitmap); 27 // Use a large bitmap. 28 const int W = 1000, H = 1000; 29 bm->setConfig(SkBitmap::kARGB_8888_Config, W, H); 30 bm->allocPixels(); 31 bm->eraseColor(SK_ColorBLACK); 32 SkCanvas canvas(*bm); 33 SkPaint paint; 34 paint.setColor(SK_ColorBLUE); 35 canvas.drawRectCoords(0, 0, SkIntToScalar(W/2), SkIntToScalar(H/2), paint); 36 return bm; 37} 38 39static SkData* create_data_from_bitmap(const SkBitmap& bm) { 40 SkDynamicMemoryWStream stream; 41 if (SkImageEncoder::EncodeStream(&stream, bm, SkImageEncoder::kPNG_Type, 100)) { 42 return stream.copyToData(); 43 } 44 return NULL; 45} 46 47static void assert_bounds_equal(skiatest::Reporter* reporter, const SkBitmap& bm1, 48 const SkBitmap& bm2) { 49 REPORTER_ASSERT(reporter, bm1.width() == bm2.width()); 50 REPORTER_ASSERT(reporter, bm1.height() == bm2.height()); 51} 52 53static void test_cache(skiatest::Reporter* reporter, SkImageCache* cache) { 54 // Test the cache directly: 55 cache->purgeAllUnpinnedCaches(); 56 intptr_t ID = SkImageCache::UNINITIALIZED_ID; 57 const size_t size = 1000; 58 char buffer[size]; 59 sk_bzero((void*) buffer, size); 60 void* memory = cache->allocAndPinCache(size, &ID); 61 if (memory != NULL) { 62 memcpy(memory, (void*)buffer, size); 63 REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) == SkImageCache::kPinned_MemoryStatus); 64 cache->releaseCache(ID); 65 REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) != SkImageCache::kPinned_MemoryStatus); 66 SkImageCache::DataStatus dataStatus; 67 memory = cache->pinCache(ID, &dataStatus); 68 if (memory != NULL) { 69 REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) 70 == SkImageCache::kPinned_MemoryStatus); 71 if (SkImageCache::kRetained_DataStatus == dataStatus) { 72 REPORTER_ASSERT(reporter, !memcmp(memory, (void*) buffer, size)); 73 } 74 cache->releaseCache(ID); 75 REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) 76 != SkImageCache::kPinned_MemoryStatus); 77 cache->purgeAllUnpinnedCaches(); 78 REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) 79 != SkImageCache::kPinned_MemoryStatus); 80 memory = cache->pinCache(ID, &dataStatus); 81 if (memory != NULL) { 82 // The memory block may or may not have survived the purging (at the 83 // memory manager's whim) so we cannot check dataStatus here. 84 cache->releaseCache(ID); 85 REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) 86 != SkImageCache::kPinned_MemoryStatus); 87 cache->throwAwayCache(ID); 88 REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) 89 == SkImageCache::kFreed_MemoryStatus); 90 } else { 91 REPORTER_ASSERT(reporter, cache->getMemoryStatus(ID) 92 == SkImageCache::kFreed_MemoryStatus); 93 } 94 } 95 } 96} 97 98static void test_factory(skiatest::Reporter* reporter, SkImageCache* cache, SkData* encodedData, 99 const SkBitmap& origBitmap) { 100 SkBitmapFactory factory(&SkImageDecoder::DecodeMemoryToTarget); 101 factory.setImageCache(cache); 102 SkAutoTDelete<SkBitmap> bitmapFromFactory(SkNEW(SkBitmap)); 103 bool success = factory.installPixelRef(encodedData, bitmapFromFactory.get()); 104 // This assumes that if the encoder worked, the decoder should also work, so the above call 105 // should not fail. 106 REPORTER_ASSERT(reporter, success); 107 assert_bounds_equal(reporter, origBitmap, *bitmapFromFactory.get()); 108 109 SkPixelRef* pixelRef = bitmapFromFactory->pixelRef(); 110 REPORTER_ASSERT(reporter, pixelRef != NULL); 111 if (NULL == cache) { 112 // This assumes that installPixelRef called lockPixels. 113 REPORTER_ASSERT(reporter, bitmapFromFactory->readyToDraw()); 114 } else { 115 // Lazy decoding 116 REPORTER_ASSERT(reporter, !bitmapFromFactory->readyToDraw()); 117 SkLazyPixelRef* lazyRef = static_cast<SkLazyPixelRef*>(pixelRef); 118 intptr_t cacheID = lazyRef->getCacheId(); 119 REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) 120 != SkImageCache::kPinned_MemoryStatus); 121 { 122 SkAutoLockPixels alp(*bitmapFromFactory.get()); 123 REPORTER_ASSERT(reporter, bitmapFromFactory->readyToDraw()); 124 cacheID = lazyRef->getCacheId(); 125 REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) 126 == SkImageCache::kPinned_MemoryStatus); 127 } 128 REPORTER_ASSERT(reporter, !bitmapFromFactory->readyToDraw()); 129 REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) 130 != SkImageCache::kPinned_MemoryStatus); 131 bitmapFromFactory.free(); 132 REPORTER_ASSERT(reporter, cache->getMemoryStatus(cacheID) 133 == SkImageCache::kFreed_MemoryStatus); 134 } 135} 136 137class ImageCacheHolder : public SkNoncopyable { 138 139public: 140 ~ImageCacheHolder() { 141 fCaches.safeUnrefAll(); 142 } 143 144 void addImageCache(SkImageCache* cache) { 145 SkSafeRef(cache); 146 *fCaches.append() = cache; 147 } 148 149 int count() const { return fCaches.count(); } 150 151 SkImageCache* getAt(int i) { 152 if (i < 0 || i > fCaches.count()) { 153 return NULL; 154 } 155 return fCaches.getAt(i); 156 } 157 158private: 159 SkTDArray<SkImageCache*> fCaches; 160}; 161 162static void TestBitmapFactory(skiatest::Reporter* reporter) { 163 SkAutoTDelete<SkBitmap> bitmap(create_bitmap()); 164 SkASSERT(bitmap.get() != NULL); 165 166 SkAutoDataUnref encodedBitmap(create_data_from_bitmap(*bitmap.get())); 167 bool encodeSucceeded = encodedBitmap.get() != NULL; 168 SkASSERT(encodeSucceeded); 169 170 ImageCacheHolder cacheHolder; 171 172 SkAutoTUnref<SkLruImageCache> lruCache(SkNEW_ARGS(SkLruImageCache, (1024 * 1024))); 173 cacheHolder.addImageCache(lruCache); 174 175 cacheHolder.addImageCache(NULL); 176 177 SkImageCache* purgeableCache = SkPurgeableImageCache::Create(); 178 if (purgeableCache != NULL) { 179 cacheHolder.addImageCache(purgeableCache); 180 purgeableCache->unref(); 181 } 182 183 for (int i = 0; i < cacheHolder.count(); i++) { 184 SkImageCache* cache = cacheHolder.getAt(i); 185 if (cache != NULL) { 186 test_cache(reporter, cache); 187 } 188 if (encodeSucceeded) { 189 test_factory(reporter, cache, encodedBitmap, *bitmap.get()); 190 } 191 } 192} 193 194#include "TestClassDef.h" 195DEFINE_TESTCLASS("BitmapFactory", TestBitmapFactoryClass, TestBitmapFactory) 196 197#endif // SK_DEBUG 198