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