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