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 "SkCanvas.h"
10 #include "SkData.h"
11 #include "SkDiscardableMemoryPool.h"
12 #include "SkImage.h"
13 #include "SkImageEncoder.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 nullptr;
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() != nullptr);
112         if (nullptr == 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, nullptr == lazy.getPixels());
122         {
123             SkAutoLockPixels autoLockPixels(lazy);  // now pixels are good.
124             REPORTER_ASSERT(reporter, lazy.getPixels());
125             if (nullptr == lazy.getPixels()) {
126                 continue;
127             }
128         }
129         // pixels should be gone!
130         REPORTER_ASSERT(reporter, nullptr == lazy.getPixels());
131         {
132             SkAutoLockPixels autoLockPixels(lazy);  // now pixels are good.
133             REPORTER_ASSERT(reporter, lazy.getPixels());
134             if (nullptr == 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_skDiscardablePixelRef(SkData * encoded,SkBitmap * dst)144 static bool install_skDiscardablePixelRef(SkData* encoded, SkBitmap* dst) {
145     // Use system-default discardable memory.
146     return SkDEPRECATED_InstallDiscardablePixelRef(encoded, dst);
147 }
148 
149 ////////////////////////////////////////////////////////////////////////////////
150 /**
151  *  This checks to see that SkDiscardablePixelRef works as advertised with a
152  *  SkDecodingImageGenerator.
153  */
DEF_TEST(DecodingImageGenerator,reporter)154 DEF_TEST(DecodingImageGenerator, reporter) {
155     test_three_encodings(reporter, install_skDiscardablePixelRef);
156 }
157 
158 class TestImageGenerator : public SkImageGenerator {
159 public:
160     enum TestType {
161         kFailGetPixels_TestType,
162         kSucceedGetPixels_TestType,
163         kLast_TestType = kSucceedGetPixels_TestType
164     };
Width()165     static int Width() { return 10; }
Height()166     static int Height() { return 10; }
167     // value choosen so that there is no loss when converting to to RGB565 and back
Color()168     static SkColor Color() { return 0xff10345a; }
PMColor()169     static SkPMColor PMColor() { return SkPreMultiplyColor(Color()); }
170 
TestImageGenerator(TestType type,skiatest::Reporter * reporter,SkColorType colorType=kN32_SkColorType)171     TestImageGenerator(TestType type, skiatest::Reporter* reporter,
172                        SkColorType colorType = kN32_SkColorType)
173     : INHERITED(GetMyInfo(colorType)), fType(type), fReporter(reporter) {
174         SkASSERT((fType <= kLast_TestType) && (fType >= 0));
175     }
~TestImageGenerator()176     virtual ~TestImageGenerator() { }
177 
178 protected:
GetMyInfo(SkColorType colorType)179     static SkImageInfo GetMyInfo(SkColorType colorType) {
180         return SkImageInfo::Make(TestImageGenerator::Width(), TestImageGenerator::Height(),
181                                  colorType, kOpaque_SkAlphaType);
182     }
183 
onGetPixels(const SkImageInfo & info,void * pixels,size_t rowBytes,SkPMColor ctable[],int * ctableCount)184     bool onGetPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
185                      SkPMColor ctable[], int* ctableCount) override {
186         REPORTER_ASSERT(fReporter, pixels != nullptr);
187         REPORTER_ASSERT(fReporter, rowBytes >= info.minRowBytes());
188         if (fType != kSucceedGetPixels_TestType) {
189             return false;
190         }
191         if (info.colorType() != kN32_SkColorType && info.colorType() != getInfo().colorType()) {
192             return false;
193         }
194         char* bytePtr = static_cast<char*>(pixels);
195         switch (info.colorType()) {
196             case kN32_SkColorType:
197                 for (int y = 0; y < info.height(); ++y) {
198                     sk_memset32((uint32_t*)bytePtr,
199                                 TestImageGenerator::PMColor(), info.width());
200                     bytePtr += rowBytes;
201                 }
202                 break;
203             case kIndex_8_SkColorType:
204                 *ctableCount = 1;
205                 ctable[0] = TestImageGenerator::PMColor();
206                 for (int y = 0; y < info.height(); ++y) {
207                     memset(bytePtr, 0, info.width());
208                     bytePtr += rowBytes;
209                 }
210                 break;
211             case kRGB_565_SkColorType:
212                 for (int y = 0; y < info.height(); ++y) {
213                     sk_memset16((uint16_t*)bytePtr,
214                         SkPixel32ToPixel16(TestImageGenerator::PMColor()), info.width());
215                     bytePtr += rowBytes;
216                 }
217                 break;
218             default:
219                 return false;
220         }
221         return true;
222     }
223 
224 private:
225     const TestType fType;
226     skiatest::Reporter* const fReporter;
227 
228     typedef SkImageGenerator INHERITED;
229 };
230 
check_test_image_generator_bitmap(skiatest::Reporter * reporter,const SkBitmap & bm)231 static void check_test_image_generator_bitmap(skiatest::Reporter* reporter,
232                                               const SkBitmap& bm) {
233     REPORTER_ASSERT(reporter, TestImageGenerator::Width() == bm.width());
234     REPORTER_ASSERT(reporter, TestImageGenerator::Height() == bm.height());
235     SkAutoLockPixels autoLockPixels(bm);
236     REPORTER_ASSERT(reporter, bm.getPixels());
237     if (nullptr == bm.getPixels()) {
238         return;
239     }
240     int errors = 0;
241     for (int y = 0; y < bm.height(); ++y) {
242         for (int x = 0; x < bm.width(); ++x) {
243             if (TestImageGenerator::Color() != bm.getColor(x, y)) {
244                 ++errors;
245             }
246         }
247     }
248     REPORTER_ASSERT(reporter, 0 == errors);
249 }
250 
check_pixelref(TestImageGenerator::TestType type,skiatest::Reporter * reporter,SkDiscardableMemory::Factory * factory,SkColorType colorType)251 static void check_pixelref(TestImageGenerator::TestType type,
252                            skiatest::Reporter* reporter,
253                            SkDiscardableMemory::Factory* factory,
254                            SkColorType colorType) {
255     SkAutoTDelete<SkImageGenerator> gen(new TestImageGenerator(type, reporter, colorType));
256     REPORTER_ASSERT(reporter, gen.get() != nullptr);
257     SkBitmap lazy;
258     bool success = SkDEPRECATED_InstallDiscardablePixelRef(gen.detach(), nullptr, &lazy, factory);
259 
260     REPORTER_ASSERT(reporter, success);
261     if (TestImageGenerator::kSucceedGetPixels_TestType == type) {
262         check_test_image_generator_bitmap(reporter, lazy);
263     } else if (TestImageGenerator::kFailGetPixels_TestType == type) {
264         SkAutoLockPixels autoLockPixels(lazy);
265         REPORTER_ASSERT(reporter, nullptr == lazy.getPixels());
266     }
267 }
268 
269 /**
270  *  This tests the basic functionality of SkDiscardablePixelRef with a
271  *  basic SkImageGenerator implementation and several
272  *  SkDiscardableMemory::Factory choices.
273  */
DEF_TEST(DiscardableAndCachingPixelRef,reporter)274 DEF_TEST(DiscardableAndCachingPixelRef, reporter) {
275     const SkColorType testColorTypes[] = {
276         kN32_SkColorType,
277         kIndex_8_SkColorType,
278         kRGB_565_SkColorType
279     };
280     for (const SkColorType testColorType : testColorTypes) {
281         check_pixelref(TestImageGenerator::kFailGetPixels_TestType, reporter, nullptr,
282                        testColorType);
283         check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType, reporter, nullptr,
284                        testColorType);
285 
286         SkAutoTUnref<SkDiscardableMemoryPool> pool(
287             SkDiscardableMemoryPool::Create(1, nullptr));
288         REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
289         check_pixelref(TestImageGenerator::kFailGetPixels_TestType, reporter, pool,
290                        testColorType);
291         REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
292         check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType, reporter, pool,
293                        testColorType);
294         REPORTER_ASSERT(reporter, 0 == pool->getRAMUsed());
295 
296         SkDiscardableMemoryPool* globalPool = SkGetGlobalDiscardableMemoryPool();
297         // Only acts differently from nullptr on a platform that has a
298         // default discardable memory implementation that differs from the
299         // global DM pool.
300         check_pixelref(TestImageGenerator::kFailGetPixels_TestType, reporter, globalPool,
301                        testColorType);
302         check_pixelref(TestImageGenerator::kSucceedGetPixels_TestType, reporter, globalPool,
303                        testColorType);
304     }
305 }
306 
307 ////////////////////////////////////////////////////////////////////////////////
308 
DEF_TEST(Image_NewFromGenerator,r)309 DEF_TEST(Image_NewFromGenerator, r) {
310     const TestImageGenerator::TestType testTypes[] = {
311         TestImageGenerator::kFailGetPixels_TestType,
312         TestImageGenerator::kSucceedGetPixels_TestType,
313     };
314     const SkColorType testColorTypes[] = {
315         kN32_SkColorType,
316         kIndex_8_SkColorType,
317         kRGB_565_SkColorType
318     };
319     for (size_t i = 0; i < SK_ARRAY_COUNT(testTypes); ++i) {
320         TestImageGenerator::TestType test = testTypes[i];
321         for (const SkColorType testColorType : testColorTypes) {
322             SkImageGenerator* gen = new TestImageGenerator(test, r, testColorType);
323             SkAutoTUnref<SkImage> image(SkImage::NewFromGenerator(gen));
324             if (nullptr == image.get()) {
325                 ERRORF(r, "SkImage::NewFromGenerator unexpecedly failed ["
326                     SK_SIZE_T_SPECIFIER "]", i);
327                 continue;
328             }
329             REPORTER_ASSERT(r, TestImageGenerator::Width() == image->width());
330             REPORTER_ASSERT(r, TestImageGenerator::Height() == image->height());
331             REPORTER_ASSERT(r, image->isLazyGenerated());
332 
333             SkBitmap bitmap;
334             bitmap.allocN32Pixels(TestImageGenerator::Width(), TestImageGenerator::Height());
335             SkCanvas canvas(bitmap);
336             const SkColor kDefaultColor = 0xffabcdef;
337             canvas.clear(kDefaultColor);
338             canvas.drawImage(image, 0, 0, nullptr);
339             if (TestImageGenerator::kSucceedGetPixels_TestType == test) {
340                 REPORTER_ASSERT(
341                     r, TestImageGenerator::Color() == bitmap.getColor(0, 0));
342             }
343             else {
344                 REPORTER_ASSERT(r, kDefaultColor == bitmap.getColor(0, 0));
345             }
346         }
347     }
348 }
349