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