1/*
2 * Copyright 2015 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 "SkCodec_libpng.h"
9#include "SkCodecPriv.h"
10#include "SkColorPriv.h"
11#include "SkColorTable.h"
12#include "SkBitmap.h"
13#include "SkMath.h"
14#include "SkScanlineDecoder.h"
15#include "SkSize.h"
16#include "SkStream.h"
17#include "SkSwizzler.h"
18
19///////////////////////////////////////////////////////////////////////////////
20// Helper macros
21///////////////////////////////////////////////////////////////////////////////
22
23#ifndef png_jmpbuf
24#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
25#endif
26
27/* These were dropped in libpng >= 1.4 */
28#ifndef png_infopp_NULL
29    #define png_infopp_NULL NULL
30#endif
31
32#ifndef png_bytepp_NULL
33    #define png_bytepp_NULL NULL
34#endif
35
36#ifndef int_p_NULL
37    #define int_p_NULL NULL
38#endif
39
40#ifndef png_flush_ptr_NULL
41    #define png_flush_ptr_NULL NULL
42#endif
43
44///////////////////////////////////////////////////////////////////////////////
45// Callback functions
46///////////////////////////////////////////////////////////////////////////////
47
48static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
49    SkCodecPrintf("------ png error %s\n", msg);
50    longjmp(png_jmpbuf(png_ptr), 1);
51}
52
53void sk_warning_fn(png_structp, png_const_charp msg) {
54    SkCodecPrintf("----- png warning %s\n", msg);
55}
56
57static void sk_read_fn(png_structp png_ptr, png_bytep data,
58                       png_size_t length) {
59    SkStream* stream = static_cast<SkStream*>(png_get_io_ptr(png_ptr));
60    const size_t bytes = stream->read(data, length);
61    if (bytes != length) {
62        // FIXME: We want to report the fact that the stream was truncated.
63        // One way to do that might be to pass a enum to longjmp so setjmp can
64        // specify the failure.
65        png_error(png_ptr, "Read Error!");
66    }
67}
68
69///////////////////////////////////////////////////////////////////////////////
70// Helpers
71///////////////////////////////////////////////////////////////////////////////
72
73class AutoCleanPng : public SkNoncopyable {
74public:
75    AutoCleanPng(png_structp png_ptr)
76        : fPng_ptr(png_ptr)
77        , fInfo_ptr(NULL) {}
78
79    ~AutoCleanPng() {
80        // fInfo_ptr will never be non-NULL unless fPng_ptr is.
81        if (fPng_ptr) {
82            png_infopp info_pp = fInfo_ptr ? &fInfo_ptr : NULL;
83            png_destroy_read_struct(&fPng_ptr, info_pp, png_infopp_NULL);
84        }
85    }
86
87    void setInfoPtr(png_infop info_ptr) {
88        SkASSERT(NULL == fInfo_ptr);
89        fInfo_ptr = info_ptr;
90    }
91
92    void detach() {
93        fPng_ptr = NULL;
94        fInfo_ptr = NULL;
95    }
96
97private:
98    png_structp     fPng_ptr;
99    png_infop       fInfo_ptr;
100};
101#define AutoCleanPng(...) SK_REQUIRE_LOCAL_VAR(AutoCleanPng)
102
103// call only if color_type is PALETTE. Returns true if the ctable has alpha
104static bool has_transparency_in_palette(png_structp png_ptr,
105                                        png_infop info_ptr) {
106    if (!png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
107        return false;
108    }
109
110    png_bytep trans;
111    int num_trans;
112    png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
113    return num_trans > 0;
114}
115
116// Method for coverting to either an SkPMColor or a similarly packed
117// unpremultiplied color.
118typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
119
120// Note: SkColorTable claims to store SkPMColors, which is not necessarily
121// the case here.
122bool SkPngCodec::decodePalette(bool premultiply, int bitDepth, int* ctableCount) {
123    int numPalette;
124    png_colorp palette;
125    png_bytep trans;
126
127    if (!png_get_PLTE(fPng_ptr, fInfo_ptr, &palette, &numPalette)) {
128        return false;
129    }
130
131    // Note: These are not necessarily SkPMColors
132    SkPMColor colorStorage[256];    // worst-case storage
133    SkPMColor* colorPtr = colorStorage;
134
135    int numTrans;
136    if (png_get_valid(fPng_ptr, fInfo_ptr, PNG_INFO_tRNS)) {
137        png_get_tRNS(fPng_ptr, fInfo_ptr, &trans, &numTrans, NULL);
138    } else {
139        numTrans = 0;
140    }
141
142    // check for bad images that might make us crash
143    if (numTrans > numPalette) {
144        numTrans = numPalette;
145    }
146
147    int index = 0;
148    int transLessThanFF = 0;
149
150    // Choose which function to use to create the color table. If the final destination's
151    // colortype is unpremultiplied, the color table will store unpremultiplied colors.
152    PackColorProc proc;
153    if (premultiply) {
154        proc = &SkPreMultiplyARGB;
155    } else {
156        proc = &SkPackARGB32NoCheck;
157    }
158    for (; index < numTrans; index++) {
159        transLessThanFF |= (int)*trans - 0xFF;
160        *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
161        palette++;
162    }
163
164    fReallyHasAlpha = transLessThanFF < 0;
165
166    for (; index < numPalette; index++) {
167        *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
168        palette++;
169    }
170
171    /*  BUGGY IMAGE WORKAROUND
172        Invalid images could contain pixel values that are greater than the number of palette
173        entries. Since we use pixel values as indices into the palette this could result in reading
174        beyond the end of the palette which could leak the contents of uninitialized memory. To
175        ensure this doesn't happen, we grow the colortable to the maximum size that can be
176        addressed by the bitdepth of the image and fill it with the last palette color or black if
177        the palette is empty (really broken image).
178    */
179    int colorCount = SkTMax(numPalette, 1 << SkTMin(bitDepth, 8));
180    SkPMColor lastColor = index > 0 ? colorPtr[-1] : SkPackARGB32(0xFF, 0, 0, 0);
181    for (; index < colorCount; index++) {
182        *colorPtr++ = lastColor;
183    }
184
185    // Set the new color count
186    if (ctableCount != NULL) {
187        *ctableCount = colorCount;
188    }
189
190    fColorTable.reset(SkNEW_ARGS(SkColorTable, (colorStorage, colorCount)));
191    return true;
192}
193
194///////////////////////////////////////////////////////////////////////////////
195// Creation
196///////////////////////////////////////////////////////////////////////////////
197
198#define PNG_BYTES_TO_CHECK 4
199
200bool SkPngCodec::IsPng(SkStream* stream) {
201    char buf[PNG_BYTES_TO_CHECK];
202    if (stream->read(buf, PNG_BYTES_TO_CHECK) != PNG_BYTES_TO_CHECK) {
203        return false;
204    }
205    if (png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
206        return false;
207    }
208    return true;
209}
210
211// Reads the header, and initializes the passed in fields, if not NULL (except
212// stream, which is passed to the read function).
213// Returns true on success, in which case the caller is responsible for calling
214// png_destroy_read_struct. If it returns false, the passed in fields (except
215// stream) are unchanged.
216static bool read_header(SkStream* stream, png_structp* png_ptrp,
217                        png_infop* info_ptrp, SkImageInfo* imageInfo) {
218    // The image is known to be a PNG. Decode enough to know the SkImageInfo.
219    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL,
220                                                 sk_error_fn, sk_warning_fn);
221    if (!png_ptr) {
222        return false;
223    }
224
225    AutoCleanPng autoClean(png_ptr);
226
227    png_infop info_ptr = png_create_info_struct(png_ptr);
228    if (info_ptr == NULL) {
229        return false;
230    }
231
232    autoClean.setInfoPtr(info_ptr);
233
234    // FIXME: Could we use the return value of setjmp to specify the type of
235    // error?
236    if (setjmp(png_jmpbuf(png_ptr))) {
237        return false;
238    }
239
240    png_set_read_fn(png_ptr, static_cast<void*>(stream), sk_read_fn);
241
242    // FIXME: This is where the old code hooks up the Peeker. Does it need to
243    // be set this early? (i.e. where are the user chunks? early in the stream,
244    // potentially?)
245    // If it does, we need to figure out a way to set it here.
246
247    // The call to png_read_info() gives us all of the information from the
248    // PNG file before the first IDAT (image data chunk).
249    png_read_info(png_ptr, info_ptr);
250    png_uint_32 origWidth, origHeight;
251    int bitDepth, colorType;
252    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
253                 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
254
255    // sanity check for size
256    {
257        int64_t size = sk_64_mul(origWidth, origHeight);
258        // now check that if we are 4-bytes per pixel, we also don't overflow
259        if (size < 0 || size > (0x7FFFFFFF >> 2)) {
260            return false;
261        }
262    }
263
264    // Tell libpng to strip 16 bit/color files down to 8 bits/color
265    if (bitDepth == 16) {
266        png_set_strip_16(png_ptr);
267    }
268#ifdef PNG_READ_PACK_SUPPORTED
269    // Extract multiple pixels with bit depths of 1, 2, and 4 from a single
270    // byte into separate bytes (useful for paletted and grayscale images).
271    if (bitDepth < 8) {
272        png_set_packing(png_ptr);
273    }
274#endif
275    // Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel.
276    if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
277        png_set_expand_gray_1_2_4_to_8(png_ptr);
278    }
279
280
281    // Now determine the default SkColorType and SkAlphaType.
282    SkColorType skColorType;
283    SkAlphaType skAlphaType;
284    switch (colorType) {
285        case PNG_COLOR_TYPE_PALETTE:
286            skColorType = kIndex_8_SkColorType;
287            skAlphaType = has_transparency_in_palette(png_ptr, info_ptr) ?
288                    kUnpremul_SkAlphaType : kOpaque_SkAlphaType;
289            break;
290        case PNG_COLOR_TYPE_GRAY:
291            if (false) {
292                // FIXME: Is this the wrong default behavior? This means if the
293                // caller supplies the info we gave them, they'll get Alpha 8.
294                skColorType = kAlpha_8_SkColorType;
295                // FIXME: Strangely, the canonical type for Alpha 8 is Premul.
296                skAlphaType = kPremul_SkAlphaType;
297            } else {
298                skColorType = kN32_SkColorType;
299                skAlphaType = kOpaque_SkAlphaType;
300            }
301            break;
302        default:
303            // Note: This *almost* mimics the code in SkImageDecoder_libpng.
304            // has_transparency_in_palette makes an additional check - whether
305            // numTrans is greater than 0. Why does the other code not make that
306            // check?
307            if (has_transparency_in_palette(png_ptr, info_ptr)
308                || PNG_COLOR_TYPE_RGB_ALPHA == colorType
309                || PNG_COLOR_TYPE_GRAY_ALPHA == colorType)
310            {
311                skAlphaType = kUnpremul_SkAlphaType;
312            } else {
313                skAlphaType = kOpaque_SkAlphaType;
314            }
315            skColorType = kN32_SkColorType;
316            break;
317    }
318
319    {
320        // FIXME: Again, this block needs to go into onGetPixels.
321        bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType && skColorType != kAlpha_8_SkColorType;
322
323        // Unless the user is requesting A8, convert a grayscale image into RGB.
324        // GRAY_ALPHA will always be converted to RGB
325        if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
326            png_set_gray_to_rgb(png_ptr);
327        }
328
329        // Add filler (or alpha) byte (after each RGB triplet) if necessary.
330        // FIXME: It seems like we could just use RGB as the SrcConfig here.
331        if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) {
332            png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
333        }
334    }
335
336    // FIXME: Also need to check for sRGB (skbug.com/3471).
337
338    if (imageInfo) {
339        *imageInfo = SkImageInfo::Make(origWidth, origHeight, skColorType,
340                                       skAlphaType);
341    }
342    autoClean.detach();
343    if (png_ptrp) {
344        *png_ptrp = png_ptr;
345    }
346    if (info_ptrp) {
347        *info_ptrp = info_ptr;
348    }
349    return true;
350}
351
352SkCodec* SkPngCodec::NewFromStream(SkStream* stream) {
353    SkAutoTDelete<SkStream> streamDeleter(stream);
354    png_structp png_ptr;
355    png_infop info_ptr;
356    SkImageInfo imageInfo;
357    if (read_header(stream, &png_ptr, &info_ptr, &imageInfo)) {
358        return SkNEW_ARGS(SkPngCodec, (imageInfo, streamDeleter.detach(), png_ptr, info_ptr));
359    }
360    return NULL;
361}
362
363#define INVALID_NUMBER_PASSES -1
364SkPngCodec::SkPngCodec(const SkImageInfo& info, SkStream* stream,
365                       png_structp png_ptr, png_infop info_ptr)
366    : INHERITED(info, stream)
367    , fPng_ptr(png_ptr)
368    , fInfo_ptr(info_ptr)
369    , fSrcConfig(SkSwizzler::kUnknown)
370    , fNumberPasses(INVALID_NUMBER_PASSES)
371    , fReallyHasAlpha(false)
372{}
373
374SkPngCodec::~SkPngCodec() {
375    this->destroyReadStruct();
376}
377
378void SkPngCodec::destroyReadStruct() {
379    if (fPng_ptr) {
380        // We will never have a NULL fInfo_ptr with a non-NULL fPng_ptr
381        SkASSERT(fInfo_ptr);
382        png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
383        fPng_ptr = NULL;
384        fInfo_ptr = NULL;
385    }
386}
387
388///////////////////////////////////////////////////////////////////////////////
389// Getting the pixels
390///////////////////////////////////////////////////////////////////////////////
391
392static bool conversion_possible(const SkImageInfo& dst, const SkImageInfo& src) {
393    // TODO: Support other conversions
394    if (dst.profileType() != src.profileType()) {
395        return false;
396    }
397
398    // Check for supported alpha types
399    if (src.alphaType() != dst.alphaType()) {
400        if (kOpaque_SkAlphaType == src.alphaType()) {
401            // If the source is opaque, we must decode to opaque
402            return false;
403        }
404
405        // The source is not opaque
406        switch (dst.alphaType()) {
407            case kPremul_SkAlphaType:
408            case kUnpremul_SkAlphaType:
409                // The source is not opaque, so either of these is okay
410                break;
411            default:
412                // We cannot decode a non-opaque image to opaque (or unknown)
413                return false;
414        }
415    }
416
417    // Check for supported color types
418    switch (dst.colorType()) {
419        // Allow output to kN32 from any type of input
420        case kN32_SkColorType:
421            return true;
422        default:
423            return dst.colorType() == src.colorType();
424    }
425}
426
427SkCodec::Result SkPngCodec::initializeSwizzler(const SkImageInfo& requestedInfo,
428                                               void* dst, size_t rowBytes,
429                                               const Options& options,
430                                               SkPMColor ctable[],
431                                               int* ctableCount) {
432    // FIXME: Could we use the return value of setjmp to specify the type of
433    // error?
434    if (setjmp(png_jmpbuf(fPng_ptr))) {
435        SkCodecPrintf("setjmp long jump!\n");
436        return kInvalidInput;
437    }
438
439    // FIXME: We already retrieved this information. Store it in SkPngCodec?
440    png_uint_32 origWidth, origHeight;
441    int bitDepth, pngColorType, interlaceType;
442    png_get_IHDR(fPng_ptr, fInfo_ptr, &origWidth, &origHeight, &bitDepth,
443                 &pngColorType, &interlaceType, int_p_NULL, int_p_NULL);
444
445    fNumberPasses = (interlaceType != PNG_INTERLACE_NONE) ?
446            png_set_interlace_handling(fPng_ptr) : 1;
447
448    // Set to the default before calling decodePalette, which may change it.
449    fReallyHasAlpha = false;
450    if (PNG_COLOR_TYPE_PALETTE == pngColorType) {
451        fSrcConfig = SkSwizzler::kIndex;
452        if (!this->decodePalette(kPremul_SkAlphaType == requestedInfo.alphaType(), bitDepth,
453                ctableCount)) {
454            return kInvalidInput;
455        }
456    } else if (kAlpha_8_SkColorType == requestedInfo.colorType()) {
457        // Note: we check the destination, since otherwise we would have
458        // told png to upscale.
459        SkASSERT(PNG_COLOR_TYPE_GRAY == pngColorType);
460        fSrcConfig = SkSwizzler::kGray;
461    } else if (this->getInfo().alphaType() == kOpaque_SkAlphaType) {
462        fSrcConfig = SkSwizzler::kRGBX;
463    } else {
464        fSrcConfig = SkSwizzler::kRGBA;
465    }
466
467    // Copy the color table to the client if they request kIndex8 mode
468    copy_color_table(requestedInfo, fColorTable, ctable, ctableCount);
469
470    // Create the swizzler.  SkPngCodec retains ownership of the color table.
471    const SkPMColor* colors = fColorTable ? fColorTable->readColors() : NULL;
472    fSwizzler.reset(SkSwizzler::CreateSwizzler(fSrcConfig, colors, requestedInfo,
473            dst, rowBytes, options.fZeroInitialized));
474    if (!fSwizzler) {
475        // FIXME: CreateSwizzler could fail for another reason.
476        return kUnimplemented;
477    }
478
479    // FIXME: Here is where we should likely insert some of the modifications
480    // made in the factory.
481    png_read_update_info(fPng_ptr, fInfo_ptr);
482
483    return kSuccess;
484}
485
486bool SkPngCodec::handleRewind() {
487    switch (this->rewindIfNeeded()) {
488        case kNoRewindNecessary_RewindState:
489            return true;
490        case kCouldNotRewind_RewindState:
491            return false;
492        case kRewound_RewindState: {
493            // This sets fPng_ptr and fInfo_ptr to NULL. If read_header
494            // succeeds, they will be repopulated, and if it fails, they will
495            // remain NULL. Any future accesses to fPng_ptr and fInfo_ptr will
496            // come through this function which will rewind and again attempt
497            // to reinitialize them.
498            this->destroyReadStruct();
499            png_structp png_ptr;
500            png_infop info_ptr;
501            if (read_header(this->stream(), &png_ptr, &info_ptr, NULL)) {
502                fPng_ptr = png_ptr;
503                fInfo_ptr = info_ptr;
504                return true;
505            }
506            return false;
507        }
508        default:
509            SkASSERT(false);
510            return false;
511    }
512}
513
514SkCodec::Result SkPngCodec::onGetPixels(const SkImageInfo& requestedInfo, void* dst,
515                                        size_t rowBytes, const Options& options,
516                                        SkPMColor ctable[], int* ctableCount) {
517    if (!this->handleRewind()) {
518        return kCouldNotRewind;
519    }
520    if (requestedInfo.dimensions() != this->getInfo().dimensions()) {
521        return kInvalidScale;
522    }
523    if (!conversion_possible(requestedInfo, this->getInfo())) {
524        return kInvalidConversion;
525    }
526
527    // Note that ctable and ctableCount may be modified if there is a color table
528    const Result result = this->initializeSwizzler(requestedInfo, dst, rowBytes,
529                                                   options, ctable, ctableCount);
530
531    if (result != kSuccess) {
532        return result;
533    }
534
535    // FIXME: Could we use the return value of setjmp to specify the type of
536    // error?
537    if (setjmp(png_jmpbuf(fPng_ptr))) {
538        SkCodecPrintf("setjmp long jump!\n");
539        return kInvalidInput;
540    }
541
542    SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
543    SkAutoMalloc storage;
544    if (fNumberPasses > 1) {
545        const int width = requestedInfo.width();
546        const int height = requestedInfo.height();
547        const int bpp = SkSwizzler::BytesPerPixel(fSrcConfig);
548        const size_t rowBytes = width * bpp;
549
550        storage.reset(width * height * bpp);
551        uint8_t* const base = static_cast<uint8_t*>(storage.get());
552
553        for (int i = 0; i < fNumberPasses; i++) {
554            uint8_t* row = base;
555            for (int y = 0; y < height; y++) {
556                uint8_t* bmRow = row;
557                png_read_rows(fPng_ptr, &bmRow, png_bytepp_NULL, 1);
558                row += rowBytes;
559            }
560        }
561
562        // Now swizzle it.
563        uint8_t* row = base;
564        for (int y = 0; y < height; y++) {
565            fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->next(row));
566            row += rowBytes;
567        }
568    } else {
569        storage.reset(requestedInfo.width() * SkSwizzler::BytesPerPixel(fSrcConfig));
570        uint8_t* srcRow = static_cast<uint8_t*>(storage.get());
571        for (int y = 0; y < requestedInfo.height(); y++) {
572            png_read_rows(fPng_ptr, &srcRow, png_bytepp_NULL, 1);
573            fReallyHasAlpha |= !SkSwizzler::IsOpaque(fSwizzler->next(srcRow));
574        }
575    }
576
577    // FIXME: do we need substituteTranspColor? Note that we cannot do it for
578    // scanline decoding, but we could do it here. Alternatively, we could do
579    // it as we go, instead of in post-processing like SkPNGImageDecoder.
580
581    this->finish();
582    return kSuccess;
583}
584
585void SkPngCodec::finish() {
586    if (setjmp(png_jmpbuf(fPng_ptr))) {
587        // We've already read all the scanlines. This is a success.
588        return;
589    }
590    /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
591    png_read_end(fPng_ptr, fInfo_ptr);
592}
593
594class SkPngScanlineDecoder : public SkScanlineDecoder {
595public:
596    SkPngScanlineDecoder(const SkImageInfo& dstInfo, SkPngCodec* codec)
597        : INHERITED(dstInfo)
598        , fCodec(codec)
599        , fHasAlpha(false)
600    {
601        fStorage.reset(dstInfo.width() * SkSwizzler::BytesPerPixel(fCodec->fSrcConfig));
602        fSrcRow = static_cast<uint8_t*>(fStorage.get());
603    }
604
605    SkImageGenerator::Result onGetScanlines(void* dst, int count, size_t rowBytes) override {
606        if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
607            SkCodecPrintf("setjmp long jump!\n");
608            return SkImageGenerator::kInvalidInput;
609        }
610
611        for (int i = 0; i < count; i++) {
612            png_read_rows(fCodec->fPng_ptr, &fSrcRow, png_bytepp_NULL, 1);
613            fCodec->fSwizzler->setDstRow(dst);
614            fHasAlpha |= !SkSwizzler::IsOpaque(fCodec->fSwizzler->next(fSrcRow));
615            dst = SkTAddOffset<void>(dst, rowBytes);
616        }
617        return SkImageGenerator::kSuccess;
618    }
619
620    SkImageGenerator::Result onSkipScanlines(int count) override {
621        // FIXME: Could we use the return value of setjmp to specify the type of
622        // error?
623        if (setjmp(png_jmpbuf(fCodec->fPng_ptr))) {
624            SkCodecPrintf("setjmp long jump!\n");
625            return SkImageGenerator::kInvalidInput;
626        }
627
628        png_read_rows(fCodec->fPng_ptr, png_bytepp_NULL, png_bytepp_NULL, count);
629        return SkImageGenerator::kSuccess;
630    }
631
632    void onFinish() override {
633        fCodec->finish();
634    }
635
636    bool onReallyHasAlpha() const override { return fHasAlpha; }
637
638private:
639    SkPngCodec*         fCodec;     // Unowned.
640    bool                fHasAlpha;
641    SkAutoMalloc        fStorage;
642    uint8_t*            fSrcRow;
643
644    typedef SkScanlineDecoder INHERITED;
645};
646
647SkScanlineDecoder* SkPngCodec::onGetScanlineDecoder(const SkImageInfo& dstInfo,
648        const Options& options, SkPMColor ctable[], int* ctableCount) {
649    if (!this->handleRewind()) {
650        return NULL;
651    }
652
653    // Check to see if scaling was requested.
654    if (dstInfo.dimensions() != this->getInfo().dimensions()) {
655        return NULL;
656    }
657
658    if (!conversion_possible(dstInfo, this->getInfo())) {
659        SkCodecPrintf("no conversion possible\n");
660        return NULL;
661    }
662
663    // Note: We set dst to NULL since we do not know it yet. rowBytes is not needed,
664    // since we'll be manually updating the dstRow, but the SkSwizzler requires it to
665    // be at least dstInfo.minRowBytes.
666    if (this->initializeSwizzler(dstInfo, NULL, dstInfo.minRowBytes(), options, ctable,
667            ctableCount) != kSuccess) {
668        SkCodecPrintf("failed to initialize the swizzler.\n");
669        return NULL;
670    }
671
672    SkASSERT(fNumberPasses != INVALID_NUMBER_PASSES);
673    if (fNumberPasses > 1) {
674        // We cannot efficiently do scanline decoding.
675        return NULL;
676    }
677
678    return SkNEW_ARGS(SkPngScanlineDecoder, (dstInfo, this));
679}
680
681