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