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