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