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 "SkResourceCache.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, b1.getPixels()); 67 REPORTER_ASSERT(reporter, 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, 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, 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 uint32_t Color() { return 0xff123456; } 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, info); 188 if ((NULL == info) || (kFailGetInfo_TestType == fType)) { 189 return false; 190 } 191 *info = SkImageInfo::MakeN32(TestImageGenerator::Width(), 192 TestImageGenerator::Height(), 193 kOpaque_SkAlphaType); 194 return true; 195 } 196 197 virtual bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes, 198 SkPMColor ctable[], int* ctableCount) SK_OVERRIDE { 199 REPORTER_ASSERT(fReporter, pixels != NULL); 200 size_t minRowBytes = static_cast<size_t>(info.width() * info.bytesPerPixel()); 201 REPORTER_ASSERT(fReporter, rowBytes >= minRowBytes); 202 if ((NULL == pixels) 203 || (fType != kSucceedGetPixels_TestType) 204 || (info.colorType() != kN32_SkColorType)) { 205 return false; 206 } 207 char* bytePtr = static_cast<char*>(pixels); 208 for (int y = 0; y < info.height(); ++y) { 209 sk_memset32(reinterpret_cast<SkColor*>(bytePtr), 210 TestImageGenerator::Color(), info.width()); 211 bytePtr += rowBytes; 212 } 213 return true; 214 } 215 216 private: 217 const TestType fType; 218 skiatest::Reporter* const fReporter; 219 }; 220 221 static void check_test_image_generator_bitmap(skiatest::Reporter* reporter, 222 const SkBitmap& bm) { 223 REPORTER_ASSERT(reporter, TestImageGenerator::Width() == bm.width()); 224 REPORTER_ASSERT(reporter, TestImageGenerator::Height() == bm.height()); 225 SkAutoLockPixels autoLockPixels(bm); 226 REPORTER_ASSERT(reporter, bm.getPixels()); 227 if (NULL == bm.getPixels()) { 228 return; 229 } 230 int errors = 0; 231 for (int y = 0; y < bm.height(); ++y) { 232 for (int x = 0; x < bm.width(); ++x) { 233 if (TestImageGenerator::Color() != *bm.getAddr32(x, y)) { 234 ++errors; 235 } 236 } 237 } 238 REPORTER_ASSERT(reporter, 0 == errors); 239 } 240 241 enum PixelRefType { 242 kSkCaching_PixelRefType, 243 kSkDiscardable_PixelRefType, 244 kLast_PixelRefType = kSkDiscardable_PixelRefType 245 }; 246 247 static void check_pixelref(TestImageGenerator::TestType type, 248 skiatest::Reporter* reporter, 249 PixelRefType pixelRefType, 250 SkDiscardableMemory::Factory* factory) { 251 SkASSERT((pixelRefType >= 0) && (pixelRefType <= kLast_PixelRefType)); 252 SkAutoTDelete<SkImageGenerator> gen(SkNEW_ARGS(TestImageGenerator, 253 (type, reporter))); 254 REPORTER_ASSERT(reporter, gen.get() != NULL); 255 SkBitmap lazy; 256 bool success; 257 if (kSkCaching_PixelRefType == pixelRefType) { 258 // Ignore factory; use global cache. 259 success = SkCachingPixelRef::Install(gen.detach(), &lazy); 260 } else { 261 success = SkInstallDiscardablePixelRef(gen.detach(), &lazy, factory); 262 } 263 REPORTER_ASSERT(reporter, success 264 == (TestImageGenerator::kFailGetInfo_TestType != type)); 265 if (TestImageGenerator::kSucceedGetPixels_TestType == type) { 266 check_test_image_generator_bitmap(reporter, lazy); 267 } else if (TestImageGenerator::kFailGetPixels_TestType == type) { 268 SkAutoLockPixels autoLockPixels(lazy); 269 REPORTER_ASSERT(reporter, NULL == lazy.getPixels()); 270 } 271 } 272 273 // new/lock/delete is an odd pattern for a pixelref, but it needs to not assert 274 static void test_newlockdelete(skiatest::Reporter* reporter) { 275 SkBitmap bm; 276 SkImageGenerator* ig = new TestImageGenerator( 277 TestImageGenerator::kSucceedGetPixels_TestType, reporter); 278 SkInstallDiscardablePixelRef(ig, &bm); 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 check_pixelref(TestImageGenerator::kFailGetInfo_TestType, 291 reporter, kSkCaching_PixelRefType, NULL); 292 check_pixelref(TestImageGenerator::kFailGetPixels_TestType, 293 reporter, kSkCaching_PixelRefType, NULL); 294 check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType, 295 reporter, kSkCaching_PixelRefType, NULL); 296 297 check_pixelref(TestImageGenerator::kFailGetInfo_TestType, 298 reporter, kSkDiscardable_PixelRefType, NULL); 299 check_pixelref(TestImageGenerator::kFailGetPixels_TestType, 300 reporter, kSkDiscardable_PixelRefType, NULL); 301 check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType, 302 reporter, kSkDiscardable_PixelRefType, NULL); 303 304 SkAutoTUnref<SkDiscardableMemoryPool> pool( 305 SkDiscardableMemoryPool::Create(1, NULL)); 306 REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed()); 307 check_pixelref(TestImageGenerator::kFailGetPixels_TestType, 308 reporter, kSkDiscardable_PixelRefType, pool); 309 REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed()); 310 check_pixelref(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 check_pixelref(TestImageGenerator::kFailGetPixels_TestType, 319 reporter, kSkDiscardable_PixelRefType, globalPool); 320 check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType, 321 reporter, kSkDiscardable_PixelRefType, globalPool); 322 } 323 324 //////////////////////////////////////////////////////////////////////////////// 325 326 DEF_TEST(Image_NewFromGenerator, r) { 327 TestImageGenerator::TestType testTypes[] = { 328 TestImageGenerator::kFailGetInfo_TestType, 329 TestImageGenerator::kFailGetPixels_TestType, 330 TestImageGenerator::kSucceedGetPixels_TestType, 331 }; 332 for (size_t i = 0; i < SK_ARRAY_COUNT(testTypes); ++i) { 333 TestImageGenerator::TestType test = testTypes[i]; 334 SkImageGenerator* gen = SkNEW_ARGS(TestImageGenerator, (test, r)); 335 SkAutoTUnref<SkImage> image(SkImage::NewFromGenerator(gen)); 336 if (TestImageGenerator::kFailGetInfo_TestType == test) { 337 REPORTER_ASSERT(r, NULL == image.get()); 338 continue; 339 } 340 if (NULL == image.get()) { 341 ERRORF(r, "SkImage::NewFromGenerator unexpecedly failed [" 342 SK_SIZE_T_SPECIFIER "]", i); 343 continue; 344 } 345 REPORTER_ASSERT(r, TestImageGenerator::Width() == image->width()); 346 REPORTER_ASSERT(r, TestImageGenerator::Height() == image->height()); 347 348 SkBitmap bitmap; 349 bitmap.allocN32Pixels(TestImageGenerator::Width(), TestImageGenerator::Height()); 350 SkCanvas canvas(bitmap); 351 const SkColor kDefaultColor = 0xffabcdef; 352 canvas.clear(kDefaultColor); 353 canvas.drawImage(image, 0, 0, NULL); 354 if (TestImageGenerator::kSucceedGetPixels_TestType == test) { 355 REPORTER_ASSERT( 356 r, TestImageGenerator::Color() == *bitmap.getAddr32(0, 0)); 357 } else { 358 REPORTER_ASSERT(r, kDefaultColor == bitmap.getColor(0,0)); 359 } 360 } 361 } 362