1/* 2 * Copyright 2015 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 "tests/Test.h" 9 10#include "include/core/SkMallocPixelRef.h" 11#include "include/core/SkPixelRef.h" 12#include "include/private/SkIDChangeListener.h" 13 14static void decrement_counter_proc(void* pixels, void* ctx) { 15 int* counter = (int*)ctx; 16 *counter -= 1; 17} 18 19static void test_dont_leak_install(skiatest::Reporter* reporter) { 20 bool success; 21 int release_counter; 22 SkImageInfo info; 23 SkBitmap bm; 24 25 info = SkImageInfo::MakeN32Premul(0, 0); 26 release_counter = 1; 27 success = bm.installPixels(info, nullptr, 0, decrement_counter_proc, &release_counter); 28 REPORTER_ASSERT(reporter, true == success); 29 bm.reset(); 30 REPORTER_ASSERT(reporter, 0 == release_counter); 31 32 info = SkImageInfo::MakeN32Premul(10, 10); 33 release_counter = 1; 34 success = bm.installPixels(info, nullptr, 0, decrement_counter_proc, &release_counter); 35 REPORTER_ASSERT(reporter, true == success); 36 bm.reset(); 37 REPORTER_ASSERT(reporter, 0 == release_counter); 38 39 info = SkImageInfo::MakeN32Premul(-10, -10); 40 release_counter = 1; 41 success = bm.installPixels(info, nullptr, 0, decrement_counter_proc, &release_counter); 42 REPORTER_ASSERT(reporter, false == success); 43 bm.reset(); 44 REPORTER_ASSERT(reporter, 0 == release_counter); 45} 46 47static void test_install(skiatest::Reporter* reporter) { 48 bool success; 49 SkImageInfo info = SkImageInfo::MakeN32Premul(0, 0); 50 SkBitmap bm; 51 // make sure we don't assert on an empty install 52 success = bm.installPixels(info, nullptr, 0); 53 REPORTER_ASSERT(reporter, success); 54 55 // no pixels should be the same as setInfo() 56 info = SkImageInfo::MakeN32Premul(10, 10); 57 success = bm.installPixels(info, nullptr, 0); 58 REPORTER_ASSERT(reporter, success); 59 60} 61 62class TestListener : public SkIDChangeListener { 63public: 64 explicit TestListener(int* ptr) : fPtr(ptr) {} 65 void changed() override { (*fPtr)++; } 66private: 67 int* fPtr; 68}; 69 70DEF_TEST(PixelRef_GenIDChange, r) { 71 SkImageInfo info = SkImageInfo::MakeN32Premul(10, 10); 72 73 sk_sp<SkPixelRef> pixelRef = SkMallocPixelRef::MakeAllocate(info, 0); 74 75 // Register a listener. 76 int count = 0; 77 pixelRef->addGenIDChangeListener(sk_make_sp<TestListener>(&count)); 78 REPORTER_ASSERT(r, 0 == count); 79 80 // No one has looked at our pixelRef's generation ID, so invalidating it doesn't make sense. 81 // (An SkPixelRef tree falls in the forest but there's nobody around to hear it. Do we care?) 82 pixelRef->notifyPixelsChanged(); 83 REPORTER_ASSERT(r, 0 == count); 84 85 // Force the generation ID to be calculated. 86 REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID()); 87 88 // Our listener was dropped in the first call to notifyPixelsChanged(). This is a no-op. 89 pixelRef->notifyPixelsChanged(); 90 REPORTER_ASSERT(r, 0 == count); 91 92 // Force the generation ID to be recalculated, then add a listener. 93 REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID()); 94 pixelRef->addGenIDChangeListener(sk_make_sp<TestListener>(&count)); 95 pixelRef->notifyPixelsChanged(); 96 REPORTER_ASSERT(r, 1 == count); 97 98 // Check that asking for deregistration causes the listener to not be called. 99 REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID()); 100 auto listener = sk_make_sp<TestListener>(&count); 101 pixelRef->addGenIDChangeListener(listener); 102 REPORTER_ASSERT(r, 1 == count); 103 listener->markShouldDeregister(); 104 pixelRef->notifyPixelsChanged(); 105 REPORTER_ASSERT(r, 1 == count); 106 107 // Check that we use deregistration to prevent unbounded growth. 108 REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID()); 109 listener = sk_make_sp<TestListener>(&count); 110 pixelRef->addGenIDChangeListener(listener); 111 REPORTER_ASSERT(r, 1 == count); 112 listener->markShouldDeregister(); 113 // Add second listener. Should deregister first listener. 114 pixelRef->addGenIDChangeListener(sk_make_sp<TestListener>(&count)); 115 REPORTER_ASSERT(r, listener->unique()); 116 117 // Quick check that nullptr is safe. 118 REPORTER_ASSERT(r, 0 != pixelRef->getGenerationID()); 119 pixelRef->addGenIDChangeListener(nullptr); 120 pixelRef->notifyPixelsChanged(); 121 122 test_install(r); 123 test_dont_leak_install(r); 124} 125