1 /* 2 * Copyright 2013 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 #include "SkBitmap.h" 9 #include "SkCanvas.h" 10 #include "SkData.h" 11 #include "SkDecodingImageGenerator.h" 12 #include "SkDiscardableMemoryPool.h" 13 #include "SkImageDecoder.h" 14 #include "SkCachingPixelRef.h" 15 #include "SkScaledImageCache.h" 16 #include "SkStream.h" 17 #include "SkUtils.h" 18 19 #include "Test.h" 20 #include "TestClassDef.h" 21 22 /** 23 * Fill this bitmap with some color. 24 */ 25 static void make_test_image(SkBitmap* bm) { 26 static const int W = 50, H = 50; 27 static const SkBitmap::Config config = SkBitmap::kARGB_8888_Config; 28 bm->setConfig(config, W, H); 29 bm->allocPixels(); 30 bm->eraseColor(SK_ColorBLACK); 31 SkCanvas canvas(*bm); 32 SkPaint paint; 33 paint.setColor(SK_ColorBLUE); 34 canvas.drawRectCoords(0, 0, SkIntToScalar(W/2), 35 SkIntToScalar(H/2), paint); 36 paint.setColor(SK_ColorWHITE); 37 canvas.drawRectCoords(SkIntToScalar(W/2), SkIntToScalar(H/2), 38 SkIntToScalar(W), SkIntToScalar(H), paint); 39 } 40 41 /** 42 * encode this bitmap into some data via SkImageEncoder 43 */ 44 static SkData* create_data_from_bitmap(const SkBitmap& bm, 45 SkImageEncoder::Type type) { 46 SkDynamicMemoryWStream stream; 47 if (SkImageEncoder::EncodeStream(&stream, bm, type, 100)) { 48 return stream.copyToData(); 49 } 50 return NULL; 51 } 52 53 //////////////////////////////////////////////////////////////////////////////// 54 55 static void compare_bitmaps(skiatest::Reporter* reporter, 56 const SkBitmap& b1, const SkBitmap& b2, 57 bool pixelPerfect = true) { 58 REPORTER_ASSERT(reporter, b1.empty() == b2.empty()); 59 REPORTER_ASSERT(reporter, b1.width() == b2.width()); 60 REPORTER_ASSERT(reporter, b1.height() == b2.height()); 61 REPORTER_ASSERT(reporter, b1.isNull() == b2.isNull()); 62 SkAutoLockPixels autoLockPixels1(b1); 63 SkAutoLockPixels autoLockPixels2(b2); 64 REPORTER_ASSERT(reporter, b1.isNull() == b2.isNull()); 65 if (b1.isNull() || b1.empty()) { 66 return; 67 } 68 REPORTER_ASSERT(reporter, NULL != b1.getPixels()); 69 REPORTER_ASSERT(reporter, NULL != b2.getPixels()); 70 if ((!(b1.getPixels())) || (!(b2.getPixels()))) { 71 return; 72 } 73 if ((b1.width() != b2.width()) || 74 (b1.height() != b2.height())) { 75 return; 76 } 77 if (!pixelPerfect) { 78 return; 79 } 80 81 int pixelErrors = 0; 82 for (int y = 0; y < b2.height(); ++y) { 83 for (int x = 0; x < b2.width(); ++x) { 84 if (b1.getColor(x, y) != b2.getColor(x, y)) { 85 ++pixelErrors; 86 } 87 } 88 } 89 REPORTER_ASSERT(reporter, 0 == pixelErrors); 90 } 91 92 typedef bool (*InstallEncoded)(SkData* encoded, SkBitmap* dst); 93 94 /** 95 This function tests three differently encoded images against the 96 original bitmap */ 97 static void test_three_encodings(skiatest::Reporter* reporter, 98 InstallEncoded install) { 99 SkBitmap original; 100 make_test_image(&original); 101 REPORTER_ASSERT(reporter, !original.empty()); 102 REPORTER_ASSERT(reporter, !original.isNull()); 103 if (original.empty() || original.isNull()) { 104 return; 105 } 106 static const SkImageEncoder::Type types[] = { 107 SkImageEncoder::kPNG_Type, 108 SkImageEncoder::kJPEG_Type, 109 SkImageEncoder::kWEBP_Type 110 }; 111 for (size_t i = 0; i < SK_ARRAY_COUNT(types); i++) { 112 SkImageEncoder::Type type = types[i]; 113 SkAutoDataUnref encoded(create_data_from_bitmap(original, type)); 114 REPORTER_ASSERT(reporter, encoded.get() != NULL); 115 if (NULL == encoded.get()) { 116 continue; 117 } 118 SkBitmap lazy; 119 bool installSuccess = install(encoded.get(), &lazy); 120 REPORTER_ASSERT(reporter, installSuccess); 121 if (!installSuccess) { 122 continue; 123 } 124 REPORTER_ASSERT(reporter, NULL == lazy.getPixels()); 125 { 126 SkAutoLockPixels autoLockPixels(lazy); // now pixels are good. 127 REPORTER_ASSERT(reporter, NULL != lazy.getPixels()); 128 if (NULL == lazy.getPixels()) { 129 continue; 130 } 131 } 132 // pixels should be gone! 133 REPORTER_ASSERT(reporter, NULL == lazy.getPixels()); 134 { 135 SkAutoLockPixels autoLockPixels(lazy); // now pixels are good. 136 REPORTER_ASSERT(reporter, NULL != lazy.getPixels()); 137 if (NULL == lazy.getPixels()) { 138 continue; 139 } 140 } 141 bool comparePixels = (SkImageEncoder::kPNG_Type == type); 142 compare_bitmaps(reporter, original, lazy, comparePixels); 143 } 144 } 145 146 //////////////////////////////////////////////////////////////////////////////// 147 static bool install_skCachingPixelRef(SkData* encoded, SkBitmap* dst) { 148 return SkCachingPixelRef::Install( 149 SkNEW_ARGS(SkDecodingImageGenerator, (encoded)), dst); 150 } 151 static bool install_skDiscardablePixelRef(SkData* encoded, SkBitmap* dst) { 152 // Use system-default discardable memory. 153 return SkDecodingImageGenerator::Install(encoded, dst, NULL); 154 } 155 156 //////////////////////////////////////////////////////////////////////////////// 157 /** 158 * This checks to see that a SkCachingPixelRef and a 159 * SkDiscardablePixelRef works as advertised with a 160 * SkDecodingImageGenerator. 161 */ 162 DEF_TEST(DecodingImageGenerator, reporter) { 163 test_three_encodings(reporter, install_skCachingPixelRef); 164 test_three_encodings(reporter, install_skDiscardablePixelRef); 165 } 166 167 //////////////////////////////////////////////////////////////////////////////// 168 namespace { 169 class TestImageGenerator : public SkImageGenerator { 170 public: 171 enum TestType { 172 kFailGetInfo_TestType, 173 kFailGetPixels_TestType, 174 kSucceedGetPixels_TestType, 175 kLast_TestType = kSucceedGetPixels_TestType 176 }; 177 static int Width() { return 10; } 178 static int Height() { return 10; } 179 static SkColor Color() { return SK_ColorCYAN; } 180 TestImageGenerator(TestType type, skiatest::Reporter* reporter) 181 : fType(type), fReporter(reporter) { 182 SkASSERT((fType <= kLast_TestType) && (fType >= 0)); 183 } 184 ~TestImageGenerator() { } 185 bool getInfo(SkImageInfo* info) SK_OVERRIDE { 186 REPORTER_ASSERT(fReporter, NULL != info); 187 if ((NULL == info) || (kFailGetInfo_TestType == fType)) { 188 return false; 189 } 190 info->fWidth = TestImageGenerator::Width(); 191 info->fHeight = TestImageGenerator::Height(); 192 info->fColorType = kPMColor_SkColorType; 193 info->fAlphaType = kOpaque_SkAlphaType; 194 return true; 195 } 196 bool getPixels(const SkImageInfo& info, 197 void* pixels, 198 size_t rowBytes) SK_OVERRIDE { 199 REPORTER_ASSERT(fReporter, pixels != NULL); 200 size_t minRowBytes 201 = static_cast<size_t>(info.fWidth * info.bytesPerPixel()); 202 REPORTER_ASSERT(fReporter, rowBytes >= minRowBytes); 203 if ((NULL == pixels) 204 || (fType != kSucceedGetPixels_TestType) 205 || (info.fColorType != kPMColor_SkColorType)) { 206 return false; 207 } 208 char* bytePtr = static_cast<char*>(pixels); 209 for (int y = 0; y < info.fHeight; ++y) { 210 sk_memset32(reinterpret_cast<SkColor*>(bytePtr), 211 TestImageGenerator::Color(), info.fWidth); 212 bytePtr += rowBytes; 213 } 214 return true; 215 } 216 private: 217 const TestType fType; 218 skiatest::Reporter* const fReporter; 219 }; 220 void CheckTestImageGeneratorBitmap(skiatest::Reporter* reporter, 221 const SkBitmap& bm) { 222 REPORTER_ASSERT(reporter, TestImageGenerator::Width() == bm.width()); 223 REPORTER_ASSERT(reporter, TestImageGenerator::Height() == bm.height()); 224 SkAutoLockPixels autoLockPixels(bm); 225 REPORTER_ASSERT(reporter, NULL != bm.getPixels()); 226 if (NULL == bm.getPixels()) { 227 return; 228 } 229 int errors = 0; 230 for (int y = 0; y < bm.height(); ++y) { 231 for (int x = 0; x < bm.width(); ++x) { 232 if (TestImageGenerator::Color() != *bm.getAddr32(x, y)) { 233 ++errors; 234 } 235 } 236 } 237 REPORTER_ASSERT(reporter, 0 == errors); 238 } 239 240 enum PixelRefType { 241 kSkCaching_PixelRefType, 242 kSkDiscardable_PixelRefType, 243 kLast_PixelRefType = kSkDiscardable_PixelRefType 244 }; 245 void CheckPixelRef(TestImageGenerator::TestType type, 246 skiatest::Reporter* reporter, 247 PixelRefType pixelRefType, 248 SkDiscardableMemory::Factory* factory) { 249 SkASSERT((pixelRefType >= 0) && (pixelRefType <= kLast_PixelRefType)); 250 SkAutoTDelete<SkImageGenerator> gen(SkNEW_ARGS(TestImageGenerator, 251 (type, reporter))); 252 REPORTER_ASSERT(reporter, gen.get() != NULL); 253 SkBitmap lazy; 254 bool success; 255 if (kSkCaching_PixelRefType == pixelRefType) { 256 // Ignore factory; use global SkScaledImageCache. 257 success = SkCachingPixelRef::Install(gen.detach(), &lazy); 258 } else { 259 success = SkInstallDiscardablePixelRef(gen.detach(), &lazy, factory); 260 } 261 REPORTER_ASSERT(reporter, success 262 == (TestImageGenerator::kFailGetInfo_TestType != type)); 263 if (TestImageGenerator::kSucceedGetPixels_TestType == type) { 264 CheckTestImageGeneratorBitmap(reporter, lazy); 265 } else if (TestImageGenerator::kFailGetPixels_TestType == type) { 266 SkAutoLockPixels autoLockPixels(lazy); 267 REPORTER_ASSERT(reporter, NULL == lazy.getPixels()); 268 } 269 } 270 } // namespace 271 272 // new/lock/delete is an odd pattern for a pixelref, but it needs to not assert 273 static void test_newlockdelete(skiatest::Reporter* reporter) { 274 SkBitmap bm; 275 SkImageGenerator* ig = new TestImageGenerator( 276 TestImageGenerator::kSucceedGetPixels_TestType, 277 reporter); 278 SkInstallDiscardablePixelRef(ig, &bm, NULL); 279 bm.pixelRef()->lockPixels(); 280 } 281 282 /** 283 * This tests the basic functionality of SkDiscardablePixelRef with a 284 * basic SkImageGenerator implementation and several 285 * SkDiscardableMemory::Factory choices. 286 */ 287 DEF_TEST(DiscardableAndCachingPixelRef, reporter) { 288 test_newlockdelete(reporter); 289 290 CheckPixelRef(TestImageGenerator::kFailGetInfo_TestType, 291 reporter, kSkCaching_PixelRefType, NULL); 292 CheckPixelRef(TestImageGenerator::kFailGetPixels_TestType, 293 reporter, kSkCaching_PixelRefType, NULL); 294 CheckPixelRef(TestImageGenerator::kSucceedGetPixels_TestType, 295 reporter, kSkCaching_PixelRefType, NULL); 296 297 CheckPixelRef(TestImageGenerator::kFailGetInfo_TestType, 298 reporter, kSkDiscardable_PixelRefType, NULL); 299 CheckPixelRef(TestImageGenerator::kFailGetPixels_TestType, 300 reporter, kSkDiscardable_PixelRefType, NULL); 301 CheckPixelRef(TestImageGenerator::kSucceedGetPixels_TestType, 302 reporter, kSkDiscardable_PixelRefType, NULL); 303 304 SkAutoTUnref<SkDiscardableMemoryPool> pool( 305 SkNEW_ARGS(SkDiscardableMemoryPool, (1, NULL))); 306 REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed()); 307 CheckPixelRef(TestImageGenerator::kFailGetPixels_TestType, 308 reporter, kSkDiscardable_PixelRefType, pool); 309 REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed()); 310 CheckPixelRef(TestImageGenerator::kSucceedGetPixels_TestType, 311 reporter, kSkDiscardable_PixelRefType, pool); 312 REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed()); 313 314 SkDiscardableMemoryPool* globalPool = SkGetGlobalDiscardableMemoryPool(); 315 // Only acts differently from NULL on a platform that has a 316 // default discardable memory implementation that differs from the 317 // global DM pool. 318 CheckPixelRef(TestImageGenerator::kFailGetPixels_TestType, 319 reporter, kSkDiscardable_PixelRefType, globalPool); 320 CheckPixelRef(TestImageGenerator::kSucceedGetPixels_TestType, 321 reporter, kSkDiscardable_PixelRefType, globalPool); 322 } 323 //////////////////////////////////////////////////////////////////////////////// 324