• 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 "Resources.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkColor.h"
12 #include "SkColorPriv.h"
13 #include "SkData.h"
14 #include "SkDecodingImageGenerator.h"
15 #include "SkDiscardableMemoryPool.h"
16 #include "SkForceLinking.h"
17 #include "SkGradientShader.h"
18 #include "SkImageDecoder.h"
19 #include "SkImageEncoder.h"
20 #include "SkImageGeneratorPriv.h"
21 #include "SkImagePriv.h"
22 #include "SkOSFile.h"
23 #include "SkPoint.h"
24 #include "SkShader.h"
25 #include "SkStream.h"
26 #include "SkString.h"
27 #include "Test.h"
28 
29 __SK_FORCE_IMAGE_DECODER_LINKING;
30 
31 /**
32  *  Interprets c as an unpremultiplied color, and returns the
33  *  premultiplied equivalent.
34  */
premultiply_unpmcolor(SkPMColor c)35 static SkPMColor premultiply_unpmcolor(SkPMColor c) {
36     U8CPU a = SkGetPackedA32(c);
37     U8CPU r = SkGetPackedR32(c);
38     U8CPU g = SkGetPackedG32(c);
39     U8CPU b = SkGetPackedB32(c);
40     return SkPreMultiplyARGB(a, r, g, b);
41 }
42 
43 /**
44  *  Return true if this stream format should be skipped, due
45  *  to do being an opaque format or not a valid format.
46  */
skip_image_format(SkImageDecoder::Format format)47 static bool skip_image_format(SkImageDecoder::Format format) {
48     switch (format) {
49         case SkImageDecoder::kPNG_Format:
50         case SkImageDecoder::kWEBP_Format:
51             return false;
52         // Skip unknown since it will not be decoded anyway.
53         case SkImageDecoder::kUnknown_Format:
54         // Technically ICO and BMP supports alpha channels, but our image
55         // decoders do not, so skip them as well.
56         case SkImageDecoder::kICO_Format:
57         case SkImageDecoder::kBMP_Format:
58         // KTX and ASTC are texture formats so it's not particularly clear how to
59         // decode the alpha from them.
60         case SkImageDecoder::kKTX_Format:
61         case SkImageDecoder::kASTC_Format:
62         // The rest of these are opaque.
63         case SkImageDecoder::kPKM_Format:
64         case SkImageDecoder::kWBMP_Format:
65         case SkImageDecoder::kGIF_Format:
66         case SkImageDecoder::kJPEG_Format:
67             return true;
68     }
69     SkASSERT(false);
70     return true;
71 }
72 
73 /**
74  *  Test decoding an image in premultiplied mode and unpremultiplied mode and compare
75  *  them.
76  */
compare_unpremul(skiatest::Reporter * reporter,const SkString & filename)77 static void compare_unpremul(skiatest::Reporter* reporter, const SkString& filename) {
78     // Decode a resource:
79     SkBitmap bm8888;
80     SkBitmap bm8888Unpremul;
81 
82     SkFILEStream stream(filename.c_str());
83 
84     SkImageDecoder::Format format = SkImageDecoder::GetStreamFormat(&stream);
85     if (skip_image_format(format)) {
86         return;
87     }
88 
89     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
90     if (NULL == decoder.get()) {
91         SkDebugf("couldn't decode %s\n", filename.c_str());
92         return;
93     }
94 
95     bool success = decoder->decode(&stream, &bm8888, kN32_SkColorType,
96                                    SkImageDecoder::kDecodePixels_Mode);
97     if (!success) {
98         return;
99     }
100 
101     success = stream.rewind();
102     REPORTER_ASSERT(reporter, success);
103     if (!success) {
104         return;
105     }
106 
107     decoder->setRequireUnpremultipliedColors(true);
108     success = decoder->decode(&stream, &bm8888Unpremul, kN32_SkColorType,
109                               SkImageDecoder::kDecodePixels_Mode);
110     if (!success) {
111         return;
112     }
113 
114     bool dimensionsMatch = bm8888.width() == bm8888Unpremul.width()
115                            && bm8888.height() == bm8888Unpremul.height();
116     REPORTER_ASSERT(reporter, dimensionsMatch);
117     if (!dimensionsMatch) {
118         return;
119     }
120 
121     // Only do the comparison if the two bitmaps are both 8888.
122     if (bm8888.colorType() != kN32_SkColorType || bm8888Unpremul.colorType() != kN32_SkColorType) {
123         return;
124     }
125 
126     // Now compare the two bitmaps.
127     for (int i = 0; i < bm8888.width(); ++i) {
128         for (int j = 0; j < bm8888.height(); ++j) {
129             // "c0" is the color of the premultiplied bitmap at (i, j).
130             const SkPMColor c0 = *bm8888.getAddr32(i, j);
131             // "c1" is the result of premultiplying the color of the unpremultiplied
132             // bitmap at (i, j).
133             const SkPMColor c1 = premultiply_unpmcolor(*bm8888Unpremul.getAddr32(i, j));
134             // Compute the difference for each component.
135             int da = SkAbs32(SkGetPackedA32(c0) - SkGetPackedA32(c1));
136             int dr = SkAbs32(SkGetPackedR32(c0) - SkGetPackedR32(c1));
137             int dg = SkAbs32(SkGetPackedG32(c0) - SkGetPackedG32(c1));
138             int db = SkAbs32(SkGetPackedB32(c0) - SkGetPackedB32(c1));
139 
140             // Alpha component must be exactly the same.
141             REPORTER_ASSERT(reporter, 0 == da);
142 
143             // Color components may not match exactly due to rounding error.
144             REPORTER_ASSERT(reporter, dr <= 1);
145             REPORTER_ASSERT(reporter, dg <= 1);
146             REPORTER_ASSERT(reporter, db <= 1);
147         }
148     }
149 }
150 
test_unpremul(skiatest::Reporter * reporter)151 static void test_unpremul(skiatest::Reporter* reporter) {
152     // This test cannot run if there is no resource path.
153     SkString resourcePath = GetResourcePath();
154     if (resourcePath.isEmpty()) {
155         SkDebugf("Could not run unpremul test because resourcePath not specified.");
156         return;
157     }
158     SkOSFile::Iter iter(resourcePath.c_str());
159     SkString basename;
160     if (iter.next(&basename)) {
161         do {
162             SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
163             // SkDebugf("about to decode \"%s\"\n", filename.c_str());
164             compare_unpremul(reporter, filename);
165         } while (iter.next(&basename));
166     } else {
167         SkDebugf("Failed to find any files :(\n");
168     }
169 }
170 
171 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
172 // Test that the alpha type is what we expect.
test_alphaType(skiatest::Reporter * reporter,const SkString & filename,bool requireUnpremul)173 static void test_alphaType(skiatest::Reporter* reporter, const SkString& filename,
174                            bool requireUnpremul) {
175     SkBitmap bm;
176     SkFILEStream stream(filename.c_str());
177 
178     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
179     if (NULL == decoder.get()) {
180         return;
181     }
182 
183     decoder->setRequireUnpremultipliedColors(requireUnpremul);
184 
185     // Decode just the bounds. This should always succeed.
186     bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
187                                    SkImageDecoder::kDecodeBounds_Mode);
188     REPORTER_ASSERT(reporter, success);
189     if (!success) {
190         return;
191     }
192 
193     // Keep track of the alpha type for testing later. If the full decode
194     // succeeds, the alpha type should be the same, unless the full decode
195     // determined that the alpha type should actually be opaque, which may
196     // not be known when only decoding the bounds.
197     const SkAlphaType boundsAlphaType = bm.alphaType();
198 
199     // rewind should always succeed on SkFILEStream.
200     success = stream.rewind();
201     REPORTER_ASSERT(reporter, success);
202     if (!success) {
203         return;
204     }
205 
206     success = decoder->decode(&stream, &bm, kN32_SkColorType, SkImageDecoder::kDecodePixels_Mode);
207 
208     if (!success) {
209         // When the decoder is set to require unpremul, if it does not support
210         // unpremul it will fail. This is the only reason the decode should
211         // fail (since we know the files we are using to test can be decoded).
212         REPORTER_ASSERT(reporter, requireUnpremul);
213         return;
214     }
215 
216     // The bounds decode should return with either the requested
217     // premul/unpremul or opaque, if that value could be determined when only
218     // decoding the bounds.
219     if (requireUnpremul) {
220         REPORTER_ASSERT(reporter, kUnpremul_SkAlphaType == boundsAlphaType
221                                   || kOpaque_SkAlphaType == boundsAlphaType);
222     } else {
223         REPORTER_ASSERT(reporter, kPremul_SkAlphaType == boundsAlphaType
224                                   || kOpaque_SkAlphaType == boundsAlphaType);
225     }
226 
227     // When decoding the full image, the alpha type should match the one
228     // returned by the bounds decode, unless the full decode determined that
229     // the alpha type is actually opaque.
230     REPORTER_ASSERT(reporter, bm.alphaType() == boundsAlphaType
231                               || bm.alphaType() == kOpaque_SkAlphaType);
232 }
233 
DEF_TEST(ImageDecoding_alphaType,reporter)234 DEF_TEST(ImageDecoding_alphaType, reporter) {
235     SkString resourcePath = GetResourcePath();
236     if (resourcePath.isEmpty()) {
237         SkDebugf("Could not run alphaType test because resourcePath not specified.");
238         return;
239     }
240 
241     SkOSFile::Iter iter(resourcePath.c_str());
242     SkString basename;
243     if (iter.next(&basename)) {
244         do {
245             SkString filename = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
246             for (int truth = 0; truth <= 1; ++truth) {
247                 test_alphaType(reporter, filename, SkToBool(truth));
248             }
249         } while (iter.next(&basename));
250     } else {
251         SkDebugf("Failed to find any files :(\n");
252     }
253 
254 }
255 
256 // Using known images, test that decoding into unpremul and premul behave as expected.
DEF_TEST(ImageDecoding_unpremul,reporter)257 DEF_TEST(ImageDecoding_unpremul, reporter) {
258     SkString resourcePath = GetResourcePath();
259     if (resourcePath.isEmpty()) {
260         SkDebugf("Could not run unpremul test because resourcePath not specified.");
261         return;
262     }
263     const char* root = "half-transparent-white-pixel";
264     const char* suffixes[] = { ".png", ".webp" };
265 
266     for (size_t i = 0; i < SK_ARRAY_COUNT(suffixes); ++i) {
267         SkString basename = SkStringPrintf("%s%s", root, suffixes[i]);
268         SkString fullName = SkOSPath::Join(resourcePath.c_str(), basename.c_str());
269 
270         SkBitmap bm;
271         SkFILEStream stream(fullName.c_str());
272 
273         if (!stream.isValid()) {
274             SkDebugf("file %s missing from resource directoy %s\n",
275                      basename.c_str(), resourcePath.c_str());
276             continue;
277         }
278 
279         // This should never fail since we know the images we're decoding.
280         SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(&stream));
281         REPORTER_ASSERT(reporter, decoder.get());
282         if (NULL == decoder.get()) {
283             continue;
284         }
285 
286         // Test unpremultiplied. We know what color this should result in.
287         decoder->setRequireUnpremultipliedColors(true);
288         bool success = decoder->decode(&stream, &bm, kN32_SkColorType,
289                                        SkImageDecoder::kDecodePixels_Mode);
290         REPORTER_ASSERT(reporter, success);
291         if (!success) {
292             continue;
293         }
294 
295         REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
296         {
297             SkAutoLockPixels alp(bm);
298             REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7fffffff);
299         }
300 
301         success = stream.rewind();
302         REPORTER_ASSERT(reporter, success);
303         if (!success) {
304             continue;
305         }
306 
307         // Test premultiplied. Once again, we know which color this should
308         // result in.
309         decoder->setRequireUnpremultipliedColors(false);
310         success = decoder->decode(&stream, &bm, kN32_SkColorType,
311                                   SkImageDecoder::kDecodePixels_Mode);
312         REPORTER_ASSERT(reporter, success);
313         if (!success) {
314             continue;
315         }
316 
317         REPORTER_ASSERT(reporter, bm.width() == 1 && bm.height() == 1);
318         {
319             SkAutoLockPixels alp(bm);
320             REPORTER_ASSERT(reporter, bm.getAddr32(0, 0)[0] == 0x7f7f7f7f);
321         }
322     }
323 }
324 #endif // SK_BUILD_FOR_UNIX/ANDROID skbug.com/2388
325 
326 #ifdef SK_DEBUG
327 // Create a stream containing a bitmap encoded to Type type.
create_image_stream(SkImageEncoder::Type type)328 static SkMemoryStream* create_image_stream(SkImageEncoder::Type type) {
329     SkBitmap bm;
330     const int size = 50;
331     bm.allocN32Pixels(size, size);
332     SkCanvas canvas(bm);
333     SkPoint points[2] = {
334         { SkIntToScalar(0), SkIntToScalar(0) },
335         { SkIntToScalar(size), SkIntToScalar(size) }
336     };
337     SkColor colors[2] = { SK_ColorWHITE, SK_ColorBLUE };
338     SkShader* shader = SkGradientShader::CreateLinear(points, colors, NULL,
339                                                       SK_ARRAY_COUNT(colors),
340                                                       SkShader::kClamp_TileMode);
341     SkPaint paint;
342     paint.setShader(shader)->unref();
343     canvas.drawPaint(paint);
344     // Now encode it to a stream.
345     SkAutoTUnref<SkData> data(SkImageEncoder::EncodeData(bm, type, 100));
346     if (NULL == data.get()) {
347         return NULL;
348     }
349     return SkNEW_ARGS(SkMemoryStream, (data.get()));
350 }
351 
352 // For every format that supports tile based decoding, ensure that
353 // calling decodeSubset will not fail if the caller has unreffed the
354 // stream provided in buildTileIndex.
355 // Only runs in debug mode since we are testing for a crash.
test_stream_life()356 static void test_stream_life() {
357     const SkImageEncoder::Type gTypes[] = {
358 #ifdef SK_BUILD_FOR_ANDROID
359         SkImageEncoder::kJPEG_Type,
360         SkImageEncoder::kPNG_Type,
361 #endif
362         SkImageEncoder::kWEBP_Type,
363     };
364     for (size_t i = 0; i < SK_ARRAY_COUNT(gTypes); ++i) {
365         // SkDebugf("encoding to %i\n", i);
366         SkAutoTUnref<SkMemoryStream> stream(create_image_stream(gTypes[i]));
367         if (NULL == stream.get()) {
368             SkDebugf("no stream\n");
369             continue;
370         }
371         SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
372         if (NULL == decoder.get()) {
373             SkDebugf("no decoder\n");
374             continue;
375         }
376         int width, height;
377         if (!decoder->buildTileIndex(stream.get(), &width, &height)) {
378             SkDebugf("could not build a tile index\n");
379             continue;
380         }
381         // Now unref the stream to make sure it survives
382         stream.reset(NULL);
383         SkBitmap bm;
384         decoder->decodeSubset(&bm, SkIRect::MakeWH(width, height), kN32_SkColorType);
385     }
386 }
387 
388 // Test inside SkScaledBitmapSampler.cpp
389 extern void test_row_proc_choice();
390 
391 #endif  // SK_DEBUG
392 
DEF_TEST(ImageDecoding,reporter)393 DEF_TEST(ImageDecoding, reporter) {
394     test_unpremul(reporter);
395 #ifdef SK_DEBUG
396     test_stream_life();
397     test_row_proc_choice();
398 #endif
399 }
400 
401 // expected output for 8x8 bitmap
402 static const int kExpectedWidth = 8;
403 static const int kExpectedHeight = 8;
404 static const SkColor kExpectedPixels[] = {
405     0xffbba570, 0xff395f5d, 0xffe25c39, 0xff197666,
406     0xff3cba27, 0xffdefcb0, 0xffc13874, 0xfffa0093,
407     0xffbda60e, 0xffc01db6, 0xff2bd688, 0xff9362d4,
408     0xffc641b2, 0xffa5cede, 0xff606eba, 0xff8f4bf3,
409     0xff3bf742, 0xff8f02a8, 0xff5509df, 0xffc7027e,
410     0xff24aa8a, 0xff886c96, 0xff625481, 0xff403689,
411     0xffc52152, 0xff78ccd6, 0xffdcb4ab, 0xff09d27d,
412     0xffca00f3, 0xff605d47, 0xff446fb2, 0xff576e46,
413     0xff273df9, 0xffb41a83, 0xfff812c3, 0xffccab67,
414     0xff034218, 0xff7db9a7, 0xff821048, 0xfffe4ab4,
415     0xff6fac98, 0xff941d27, 0xff5fe411, 0xfffbb283,
416     0xffd86e99, 0xff169162, 0xff71128c, 0xff39cab4,
417     0xffa7fe63, 0xff4c956b, 0xffbc22e0, 0xffb272e4,
418     0xff129f4a, 0xffe34513, 0xff3d3742, 0xffbd190a,
419     0xffb07222, 0xff2e23f8, 0xfff089d9, 0xffb35738,
420     0xffa86022, 0xff3340fe, 0xff95fe71, 0xff6a71df
421 };
422 SK_COMPILE_ASSERT((kExpectedWidth * kExpectedHeight)
423                   == SK_ARRAY_COUNT(kExpectedPixels), array_size_mismatch);
424 
DEF_TEST(WebP,reporter)425 DEF_TEST(WebP, reporter) {
426     const unsigned char encodedWebP[] = {
427         0x52, 0x49, 0x46, 0x46, 0x2c, 0x01, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50,
428         0x56, 0x50, 0x38, 0x4c, 0x20, 0x01, 0x00, 0x00, 0x2f, 0x07, 0xc0, 0x01,
429         0x00, 0xff, 0x01, 0x45, 0x03, 0x00, 0xe2, 0xd5, 0xae, 0x60, 0x2b, 0xad,
430         0xd9, 0x68, 0x76, 0xb6, 0x8d, 0x6a, 0x1d, 0xc0, 0xe6, 0x19, 0xd6, 0x16,
431         0xb7, 0xb4, 0xef, 0xcf, 0xc3, 0x15, 0x6c, 0xb3, 0xbd, 0x77, 0x0d, 0x85,
432         0x6d, 0x1b, 0xa9, 0xb1, 0x2b, 0xdc, 0x3d, 0x83, 0xdb, 0x00, 0x00, 0xc8,
433         0x26, 0xe5, 0x01, 0x99, 0x8a, 0xd5, 0xdd, 0xfc, 0x82, 0xcd, 0xcd, 0x9a,
434         0x8c, 0x13, 0xcc, 0x1b, 0xba, 0xf5, 0x05, 0xdb, 0xee, 0x6a, 0xdb, 0x38,
435         0x60, 0xfe, 0x43, 0x2c, 0xd4, 0x6a, 0x99, 0x4d, 0xc6, 0xc0, 0xd3, 0x28,
436         0x1b, 0xc1, 0xb1, 0x17, 0x4e, 0x43, 0x0e, 0x3d, 0x27, 0xe9, 0xe4, 0x84,
437         0x4f, 0x24, 0x62, 0x69, 0x85, 0x43, 0x8d, 0xc2, 0x04, 0x00, 0x07, 0x59,
438         0x60, 0xfd, 0x8b, 0x4d, 0x60, 0x32, 0x72, 0xcf, 0x88, 0x0c, 0x2f, 0x2f,
439         0xad, 0x62, 0xbd, 0x27, 0x09, 0x16, 0x70, 0x78, 0x6c, 0xd9, 0x82, 0xef,
440         0x1a, 0xa2, 0xcc, 0xf0, 0xf1, 0x6f, 0xd8, 0x78, 0x2e, 0x39, 0xa1, 0xcf,
441         0x14, 0x4b, 0x89, 0xb4, 0x1b, 0x48, 0x15, 0x7c, 0x48, 0x6f, 0x8c, 0x20,
442         0xb7, 0x00, 0xcf, 0xfc, 0xdb, 0xd0, 0xe9, 0xe7, 0x42, 0x09, 0xa4, 0x03,
443         0x40, 0xac, 0xda, 0x40, 0x01, 0x00, 0x5f, 0xa1, 0x3d, 0x64, 0xe1, 0xf4,
444         0x03, 0x45, 0x29, 0xe0, 0xe2, 0x4a, 0xc3, 0xa2, 0xe8, 0xe0, 0x25, 0x12,
445         0x74, 0xc6, 0xe8, 0xfb, 0x93, 0x4f, 0x9f, 0x5e, 0xc0, 0xa6, 0x91, 0x1b,
446         0xa4, 0x24, 0x82, 0xc3, 0x61, 0x07, 0x4c, 0x49, 0x4f, 0x53, 0xae, 0x5f,
447         0x5d, 0x39, 0x36, 0xc0, 0x5b, 0x57, 0x54, 0x60, 0x10, 0x00, 0x00, 0xd1,
448         0x68, 0xb6, 0x6d, 0xdb, 0x36, 0x22, 0xfa, 0x1f, 0x35, 0x75, 0x22, 0xec,
449         0x31, 0xbc, 0x5d, 0x8f, 0x87, 0x53, 0xa2, 0x05, 0x8c, 0x2f, 0xcd, 0xa8,
450         0xa7, 0xf3, 0xa3, 0xbd, 0x83, 0x8b, 0x2a, 0xc8, 0x58, 0xf5, 0xac, 0x80,
451         0xe3, 0xfe, 0x66, 0xa4, 0x7c, 0x1b, 0x6c, 0xd1, 0xa9, 0xd8, 0x14, 0xd0,
452         0xc5, 0xb5, 0x39, 0x71, 0x97, 0x19, 0x19, 0x1b
453     };
454     SkAutoDataUnref encoded(SkData::NewWithCopy(encodedWebP,
455                                                 sizeof(encodedWebP)));
456     SkBitmap bm;
457 
458     bool success = SkInstallDiscardablePixelRef(
459         SkDecodingImageGenerator::Create(encoded,
460             SkDecodingImageGenerator::Options()), &bm);
461 
462     REPORTER_ASSERT(reporter, success);
463     if (!success) {
464         return;
465     }
466     SkAutoLockPixels alp(bm);
467 
468     bool rightSize = ((kExpectedWidth == bm.width())
469                       && (kExpectedHeight == bm.height()));
470     REPORTER_ASSERT(reporter, rightSize);
471     if (rightSize) {
472         bool error = false;
473         const SkColor* correctPixel = kExpectedPixels;
474         for (int y = 0; y < bm.height(); ++y) {
475             for (int x = 0; x < bm.width(); ++x) {
476                 error |= (*correctPixel != bm.getColor(x, y));
477                 ++correctPixel;
478             }
479         }
480         REPORTER_ASSERT(reporter, !error);
481     }
482 }
483 
484 ////////////////////////////////////////////////////////////////////////////////
485 
486 // example of how Android will do this inside their BitmapFactory
install_pixel_ref(SkBitmap * bitmap,SkStreamRewindable * stream,int sampleSize,bool ditherImage)487 static SkPixelRef* install_pixel_ref(SkBitmap* bitmap,
488                                      SkStreamRewindable* stream,
489                                      int sampleSize, bool ditherImage) {
490     SkASSERT(bitmap != NULL);
491     SkASSERT(stream != NULL);
492     SkASSERT(stream->rewind());
493     SkASSERT(stream->unique());
494     SkColorType colorType = bitmap->colorType();
495     SkDecodingImageGenerator::Options opts(sampleSize, ditherImage, colorType);
496     if (SkInstallDiscardablePixelRef(
497                 SkDecodingImageGenerator::Create(stream, opts), bitmap)) {
498         return bitmap->pixelRef();
499     }
500     return NULL;
501 }
502 /**
503  *  A test for the SkDecodingImageGenerator::Create and
504  *  SkInstallDiscardablePixelRef functions.
505  */
DEF_TEST(ImprovedBitmapFactory,reporter)506 DEF_TEST(ImprovedBitmapFactory, reporter) {
507     SkString pngFilename = GetResourcePath("randPixels.png");
508     SkAutoTUnref<SkStreamRewindable> stream(SkStream::NewFromFile(pngFilename.c_str()));
509     if (sk_exists(pngFilename.c_str())) {
510         SkBitmap bm;
511         SkAssertResult(bm.setInfo(SkImageInfo::MakeN32Premul(1, 1)));
512         REPORTER_ASSERT(reporter,
513             install_pixel_ref(&bm, stream.detach(), 1, true));
514         SkAutoLockPixels alp(bm);
515         REPORTER_ASSERT(reporter, bm.getPixels());
516     }
517 }
518 
519 
520 ////////////////////////////////////////////////////////////////////////////////
521 
522 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
check_rounding(int value,int dividend,int divisor)523 static inline bool check_rounding(int value, int dividend, int divisor) {
524     // returns true if the value is greater than floor(dividend/divisor)
525     // and less than SkNextPow2(ceil(dividend - divisor))
526     return (((divisor * value) > (dividend - divisor))
527             && value <= SkNextPow2(((dividend - 1) / divisor) + 1));
528 }
529 #endif  // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
530 
531 
532 #if SK_PMCOLOR_BYTE_ORDER(B,G,R,A)
533     #define kBackwards_SkColorType kRGBA_8888_SkColorType
534 #elif SK_PMCOLOR_BYTE_ORDER(R,G,B,A)
535     #define kBackwards_SkColorType kBGRA_8888_SkColorType
536 #else
537     #error "SK_*32_SHFIT values must correspond to BGRA or RGBA byte order"
538 #endif
539 
SkColorType_to_string(SkColorType colorType)540 static inline const char* SkColorType_to_string(SkColorType colorType) {
541     switch(colorType) {
542         case kAlpha_8_SkColorType:   return "Alpha_8";
543         case kRGB_565_SkColorType:   return "RGB_565";
544         case kARGB_4444_SkColorType: return "ARGB_4444";
545         case kN32_SkColorType:       return "N32";
546         case kBackwards_SkColorType: return "Backwards";
547         case kIndex_8_SkColorType:   return "Index_8";
548         default:                     return "ERROR";
549     }
550 }
551 
options_colorType(const SkDecodingImageGenerator::Options & opts)552 static inline const char* options_colorType(
553         const SkDecodingImageGenerator::Options& opts) {
554     if (opts.fUseRequestedColorType) {
555         return SkColorType_to_string(opts.fRequestedColorType);
556     } else {
557         return "(none)";
558     }
559 }
560 
yn(bool value)561 static inline const char* yn(bool value) {
562     if (value) {
563         return "yes";
564     } else {
565         return "no";
566     }
567 }
568 
569 /**
570  * Given either a SkStream or a SkData, try to decode the encoded
571  * image using the specified options and report errors.
572  */
test_options(skiatest::Reporter * reporter,const SkDecodingImageGenerator::Options & opts,SkStreamRewindable * encodedStream,SkData * encodedData,bool useData,const SkString & path)573 static void test_options(skiatest::Reporter* reporter,
574                          const SkDecodingImageGenerator::Options& opts,
575                          SkStreamRewindable* encodedStream,
576                          SkData* encodedData,
577                          bool useData,
578                          const SkString& path) {
579     SkBitmap bm;
580     bool success = false;
581     if (useData) {
582         if (NULL == encodedData) {
583             return;
584         }
585         success = SkInstallDiscardablePixelRef(
586             SkDecodingImageGenerator::Create(encodedData, opts), &bm);
587     } else {
588         if (NULL == encodedStream) {
589             return;
590         }
591         success = SkInstallDiscardablePixelRef(
592             SkDecodingImageGenerator::Create(encodedStream->duplicate(), opts), &bm);
593     }
594     if (!success) {
595         if (opts.fUseRequestedColorType
596             && (kARGB_4444_SkColorType == opts.fRequestedColorType)) {
597             return;  // Ignore known conversion inabilities.
598         }
599         // If we get here, it's a failure and we will need more
600         // information about why it failed.
601         ERRORF(reporter, "Bounds decode failed [sampleSize=%d dither=%s "
602                "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
603                options_colorType(opts), path.c_str());
604         return;
605     }
606     #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_UNIX)
607     // Android is the only system that use Skia's image decoders in
608     // production.  For now, we'll only verify that samplesize works
609     // on systems where it already is known to work.
610     REPORTER_ASSERT(reporter, check_rounding(bm.height(), kExpectedHeight,
611                                              opts.fSampleSize));
612     REPORTER_ASSERT(reporter, check_rounding(bm.width(), kExpectedWidth,
613                                              opts.fSampleSize));
614     // The ImageDecoder API doesn't guarantee that SampleSize does
615     // anything at all, but the decoders that this test excercises all
616     // produce an output size in the following range:
617     //    (((sample_size * out_size) > (in_size - sample_size))
618     //     && out_size <= SkNextPow2(((in_size - 1) / sample_size) + 1));
619     #endif  // SK_BUILD_FOR_ANDROID || SK_BUILD_FOR_UNIX
620     SkAutoLockPixels alp(bm);
621     if (bm.getPixels() == NULL) {
622         ERRORF(reporter, "Pixel decode failed [sampleSize=%d dither=%s "
623                "colorType=%s %s]", opts.fSampleSize, yn(opts.fDitherImage),
624                options_colorType(opts), path.c_str());
625         return;
626     }
627 
628     SkColorType requestedColorType = opts.fRequestedColorType;
629     REPORTER_ASSERT(reporter,
630                     (!opts.fUseRequestedColorType)
631                     || (bm.colorType() == requestedColorType));
632 
633     // Condition under which we should check the decoding results:
634     if ((kN32_SkColorType == bm.colorType())
635         && (!path.endsWith(".jpg"))  // lossy
636         && (opts.fSampleSize == 1)) {  // scaled
637         const SkColor* correctPixels = kExpectedPixels;
638         SkASSERT(bm.height() == kExpectedHeight);
639         SkASSERT(bm.width() == kExpectedWidth);
640         int pixelErrors = 0;
641         for (int y = 0; y < bm.height(); ++y) {
642             for (int x = 0; x < bm.width(); ++x) {
643                 if (*correctPixels != bm.getColor(x, y)) {
644                     ++pixelErrors;
645                 }
646                 ++correctPixels;
647             }
648         }
649         if (pixelErrors != 0) {
650             ERRORF(reporter, "Pixel-level mismatch (%d of %d) "
651                    "[sampleSize=%d dither=%s colorType=%s %s]",
652                    pixelErrors, kExpectedHeight * kExpectedWidth,
653                    opts.fSampleSize, yn(opts.fDitherImage),
654                    options_colorType(opts), path.c_str());
655         }
656     }
657 }
658 
659 /**
660  *  SkDecodingImageGenerator has an Options struct which lets the
661  *  client of the generator set sample size, dithering, and bitmap
662  *  config.  This test loops through many possible options and tries
663  *  them on a set of 5 small encoded images (each in a different
664  *  format).  We test both SkData and SkStreamRewindable decoding.
665  */
DEF_TEST(ImageDecoderOptions,reporter)666 DEF_TEST(ImageDecoderOptions, reporter) {
667     const char* files[]  = {
668         "randPixels.bmp",
669         "randPixels.jpg",
670         "randPixels.png",
671         "randPixels.webp",
672         #if !defined(SK_BUILD_FOR_WIN)
673         // TODO(halcanary): Find out why this fails sometimes.
674         "randPixels.gif",
675         #endif
676     };
677 
678     SkString resourceDir = GetResourcePath();
679     if (!sk_exists(resourceDir.c_str())) {
680         return;
681     }
682 
683     int scaleList[] = {1, 2, 3, 4};
684     bool ditherList[] = {true, false};
685     SkColorType colorList[] = {
686         kAlpha_8_SkColorType,
687         kRGB_565_SkColorType,
688         kARGB_4444_SkColorType,  // Most decoders will fail on 4444.
689         kN32_SkColorType
690         // Note that indexed color is left out of the list.  Lazy
691         // decoding doesn't do indexed color.
692     };
693     const bool useDataList[] = {true, false};
694 
695     for (size_t fidx = 0; fidx < SK_ARRAY_COUNT(files); ++fidx) {
696         SkString path = SkOSPath::Join(resourceDir.c_str(), files[fidx]);
697         if (!sk_exists(path.c_str())) {
698             continue;
699         }
700 
701         SkAutoDataUnref encodedData(SkData::NewFromFileName(path.c_str()));
702         REPORTER_ASSERT(reporter, encodedData.get() != NULL);
703         SkAutoTUnref<SkStreamRewindable> encodedStream(
704             SkStream::NewFromFile(path.c_str()));
705         REPORTER_ASSERT(reporter, encodedStream.get() != NULL);
706 
707         for (size_t i = 0; i < SK_ARRAY_COUNT(scaleList); ++i) {
708             for (size_t j = 0; j < SK_ARRAY_COUNT(ditherList); ++j) {
709                 for (size_t m = 0; m < SK_ARRAY_COUNT(useDataList); ++m) {
710                     for (size_t k = 0; k < SK_ARRAY_COUNT(colorList); ++k) {
711                         SkDecodingImageGenerator::Options opts(scaleList[i],
712                                                                ditherList[j],
713                                                                colorList[k]);
714                         test_options(reporter, opts, encodedStream, encodedData,
715                                      useDataList[m], path);
716 
717                     }
718                     SkDecodingImageGenerator::Options options(scaleList[i],
719                                                               ditherList[j]);
720                     test_options(reporter, options, encodedStream, encodedData,
721                                  useDataList[m], path);
722                 }
723             }
724         }
725     }
726 }
727 
DEF_TEST(DiscardablePixelRef_SecondLockColorTableCheck,r)728 DEF_TEST(DiscardablePixelRef_SecondLockColorTableCheck, r) {
729     SkString resourceDir = GetResourcePath();
730     SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.gif");
731     if (!sk_exists(path.c_str())) {
732         return;
733     }
734     SkAutoDataUnref encoded(SkData::NewFromFileName(path.c_str()));
735     SkBitmap bitmap;
736     if (!SkInstallDiscardablePixelRef(
737             SkDecodingImageGenerator::Create(
738                     encoded, SkDecodingImageGenerator::Options()), &bitmap)) {
739         #ifndef SK_BUILD_FOR_WIN
740         ERRORF(r, "SkInstallDiscardablePixelRef [randPixels.gif] failed.");
741         #endif
742         return;
743     }
744     if (kIndex_8_SkColorType != bitmap.colorType()) {
745         return;
746     }
747     {
748         SkAutoLockPixels alp(bitmap);
749         REPORTER_ASSERT(r, bitmap.getColorTable() && "first pass");
750     }
751     {
752         SkAutoLockPixels alp(bitmap);
753         REPORTER_ASSERT(r, bitmap.getColorTable() && "second pass");
754     }
755 }
756 
757 
758 ////////////////////////////////////////////////////////////////////////////////
759 namespace {
760 class SingleAllocator : public SkBitmap::Allocator {
761 public:
SingleAllocator(void * p,size_t s)762     SingleAllocator(void* p, size_t s) : fPixels(p), fSize(s) { }
~SingleAllocator()763     ~SingleAllocator() {}
764     // If the pixels in fPixels are big enough, use them.
allocPixelRef(SkBitmap * bm,SkColorTable * ct)765     virtual bool allocPixelRef(SkBitmap* bm, SkColorTable* ct) SK_OVERRIDE {
766         SkASSERT(bm);
767         if (bm->info().getSafeSize(bm->rowBytes()) <= fSize) {
768             bm->setPixels(fPixels, ct);
769             fPixels = NULL;
770             fSize = 0;
771             return true;
772         }
773         return bm->tryAllocPixels(NULL, ct);
774     }
ready()775     bool ready() { return fPixels != NULL; }
776 private:
777     void* fPixels;
778     size_t fSize;
779 };
780 }  // namespace
781 
782 /*  This tests for a bug in libjpeg where INT32 is typedefed to long
783     and memory can be written to outside of the array. */
DEF_TEST(ImageDecoding_JpegOverwrite,r)784 DEF_TEST(ImageDecoding_JpegOverwrite, r) {
785     SkString resourceDir = GetResourcePath();
786     SkString path = SkOSPath::Join(resourceDir.c_str(), "randPixels.jpg");
787     SkAutoTUnref<SkStreamAsset> stream(
788             SkStream::NewFromFile(path.c_str()));
789     if (!stream.get()) {
790         SkDebugf("\nPath '%s' missing.\n", path.c_str());
791         return;
792     }
793     SkAutoTDelete<SkImageDecoder> decoder(SkImageDecoder::Factory(stream));
794     if (NULL == decoder.get()) {
795         ERRORF(r, "\nSkImageDecoder::Factory failed.\n");
796         return;
797     }
798     SkAssertResult(stream->rewind());
799 
800     static const uint16_t sentinal = 0xBEEF;
801     static const int pixelCount = 16;
802     SkAutoTMalloc<uint16_t> pixels(pixelCount + 1);
803     // pixels.get() should be 4-byte aligned.
804     // This is necessary to reproduce the bug.
805 
806     pixels[pixelCount] = sentinal;  // This value should not be changed.
807 
808     SkAutoTUnref<SingleAllocator> allocator(
809             SkNEW_ARGS(SingleAllocator,
810                        ((void*)pixels.get(), sizeof(uint16_t) * pixelCount)));
811     decoder->setAllocator(allocator);
812     decoder->setSampleSize(2);
813     SkBitmap bitmap;
814     bool success = decoder->decode(stream, &bitmap, kRGB_565_SkColorType,
815                                    SkImageDecoder::kDecodePixels_Mode);
816     REPORTER_ASSERT(r, success);
817     REPORTER_ASSERT(r, !allocator->ready());  // Decoder used correct memory
818     REPORTER_ASSERT(r, sentinal == pixels[pixelCount]);
819 }
820