| Index: src/images/SkImageDecoder_libpng.cpp | 
| diff --git a/src/images/SkImageDecoder_libpng.cpp b/src/images/SkImageDecoder_libpng.cpp | 
| index d59a67bf8ef8090e4268de40a788c04086e7d087..4c44b9109caadc6deba3cbea737c15239dbf7aff 100644 | 
| --- a/src/images/SkImageDecoder_libpng.cpp | 
| +++ b/src/images/SkImageDecoder_libpng.cpp | 
| @@ -42,18 +42,24 @@ extern "C" { | 
|  | 
| class SkPNGImageIndex { | 
| public: | 
| -    SkPNGImageIndex(png_structp png_ptr, png_infop info_ptr) { | 
| -        this->png_ptr = png_ptr; | 
| -        this->info_ptr = info_ptr; | 
| +    SkPNGImageIndex(SkStream* stream, png_structp png_ptr, png_infop info_ptr) | 
| +        : fStream(stream) | 
| +        , fPng_ptr(png_ptr) | 
| +        , fInfo_ptr(info_ptr) | 
| +        , fConfig(SkBitmap::kNo_Config) { | 
| +        SkASSERT(stream != NULL); | 
| +        stream->ref(); | 
| } | 
| ~SkPNGImageIndex() { | 
| -        if (NULL != png_ptr) { | 
| -            png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL); | 
| +        if (NULL != fPng_ptr) { | 
| +            png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL); | 
| } | 
| } | 
|  | 
| -    png_structp png_ptr; | 
| -    png_infop info_ptr; | 
| +    SkAutoTUnref<SkStream>  fStream; | 
| +    png_structp             fPng_ptr; | 
| +    png_infop               fInfo_ptr; | 
| +    SkBitmap::Config        fConfig; | 
| }; | 
|  | 
| class SkPNGImageDecoder : public SkImageDecoder { | 
| @@ -261,10 +267,6 @@ bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp, | 
| png_set_expand_gray_1_2_4_to_8(png_ptr); | 
| } | 
|  | 
| -    /* Make a grayscale image into RGB. */ | 
| -    if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { | 
| -        png_set_gray_to_rgb(png_ptr); | 
| -    } | 
| return true; | 
| } | 
|  | 
| @@ -326,11 +328,6 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, | 
|  | 
| SkAutoLockPixels alp(*decodedBitmap); | 
|  | 
| -    /* Add filler (or alpha) byte (before/after each RGB triplet) */ | 
| -    if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY) { | 
| -        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | 
| -    } | 
| - | 
| /* Turn on interlace handling.  REQUIRED if you are not using | 
| *  png_read_image().  To see how to handle interlacing passes, | 
| *  see the png_read_row() method below: | 
| @@ -344,7 +341,11 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, | 
| */ | 
| png_read_update_info(png_ptr, info_ptr); | 
|  | 
| -    if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { | 
| +    if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config) | 
| +        && 1 == sampleSize) { | 
| +        // A8 is only allowed if the original was GRAY. | 
| +        SkASSERT(config != SkBitmap::kA8_Config | 
| +                 || PNG_COLOR_TYPE_GRAY == colorType); | 
| for (int i = 0; i < number_passes; i++) { | 
| for (png_uint_32 y = 0; y < origHeight; y++) { | 
| uint8_t* bmRow = decodedBitmap->getAddr8(0, y); | 
| @@ -358,6 +359,11 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, | 
| if (colorTable != NULL) { | 
| sc = SkScaledBitmapSampler::kIndex; | 
| srcBytesPerPixel = 1; | 
| +        } else if (SkBitmap::kA8_Config == config) { | 
| +            // A8 is only allowed if the original was GRAY. | 
| +            SkASSERT(PNG_COLOR_TYPE_GRAY == colorType); | 
| +            sc = SkScaledBitmapSampler::kGray; | 
| +            srcBytesPerPixel = 1; | 
| } else if (hasAlpha) { | 
| sc = SkScaledBitmapSampler::kRGBA; | 
| } else { | 
| @@ -436,8 +442,10 @@ bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap, | 
|  | 
|  | 
| bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, | 
| -                                        SkBitmap::Config *configp, bool * SK_RESTRICT hasAlphap, | 
| -                                        bool *doDitherp, SkPMColor *theTranspColorp) { | 
| +                                        SkBitmap::Config* SK_RESTRICT configp, | 
| +                                        bool* SK_RESTRICT hasAlphap, | 
| +                                        bool* SK_RESTRICT doDitherp, | 
| +                                        SkPMColor* SK_RESTRICT theTranspColorp) { | 
| png_uint_32 origWidth, origHeight; | 
| int bitDepth, colorType; | 
| png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth, | 
| @@ -510,7 +518,14 @@ bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, | 
| PNG_COLOR_TYPE_GRAY_ALPHA == colorType) { | 
| *hasAlphap = true; | 
| } | 
| -        *configp = this->getPrefConfig(k32Bit_SrcDepth, *hasAlphap); | 
| + | 
| +        SrcDepth srcDepth = k32Bit_SrcDepth; | 
| +        if (PNG_COLOR_TYPE_GRAY == colorType) { | 
| +            srcDepth = k8BitGray_SrcDepth; | 
| +            SkASSERT(!*hasAlphap); | 
| +        } | 
| + | 
| +        *configp = this->getPrefConfig(srcDepth, *hasAlphap); | 
| // now match the request against our capabilities | 
| if (*hasAlphap) { | 
| if (*configp != SkBitmap::kARGB_4444_Config) { | 
| @@ -518,7 +533,8 @@ bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, | 
| } | 
| } else { | 
| if (*configp != SkBitmap::kRGB_565_Config && | 
| -                *configp != SkBitmap::kARGB_4444_Config) { | 
| +                *configp != SkBitmap::kARGB_4444_Config && | 
| +                *configp != SkBitmap::kA8_Config) { | 
| *configp = SkBitmap::kARGB_8888_Config; | 
| } | 
| } | 
| @@ -546,6 +562,33 @@ bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr, | 
| if (this->getRequireUnpremultipliedColors() && *hasAlphap) { | 
| *configp = SkBitmap::kARGB_8888_Config; | 
| } | 
| + | 
| +    if (fImageIndex != NULL) { | 
| +        if (SkBitmap::kNo_Config == fImageIndex->fConfig) { | 
| +            // This is the first time for this subset decode. From now on, | 
| +            // all decodes must be in the same config. | 
| +            fImageIndex->fConfig = *configp; | 
| +        } else if (fImageIndex->fConfig != *configp) { | 
| +            // Requesting a different config for a subsequent decode is not | 
| +            // supported. Report failure before we make changes to png_ptr. | 
| +            return false; | 
| +        } | 
| +    } | 
| + | 
| +    bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType | 
| +                            && *configp != SkBitmap::kA8_Config; | 
| + | 
| +    // Unless the user is requesting A8, convert a grayscale image into RGB. | 
| +    // GRAY_ALPHA will always be converted to RGB | 
| +    if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) { | 
| +        png_set_gray_to_rgb(png_ptr); | 
| +    } | 
| + | 
| +    // Add filler (or alpha) byte (after each RGB triplet) if necessary. | 
| +    if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) { | 
| +        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | 
| +    } | 
| + | 
| return true; | 
| } | 
|  | 
| @@ -647,7 +690,7 @@ bool SkPNGImageDecoder::onBuildTileIndex(SkStream* sk_stream, int *width, int *h | 
| if (fImageIndex) { | 
| SkDELETE(fImageIndex); | 
| } | 
| -    fImageIndex = SkNEW_ARGS(SkPNGImageIndex, (png_ptr, info_ptr)); | 
| +    fImageIndex = SkNEW_ARGS(SkPNGImageIndex, (sk_stream, png_ptr, info_ptr)); | 
|  | 
| return true; | 
| } | 
| @@ -657,8 +700,8 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 
| return false; | 
| } | 
|  | 
| -    png_structp png_ptr = fImageIndex->png_ptr; | 
| -    png_infop info_ptr = fImageIndex->info_ptr; | 
| +    png_structp png_ptr = fImageIndex->fPng_ptr; | 
| +    png_infop info_ptr = fImageIndex->fInfo_ptr; | 
| if (setjmp(png_jmpbuf(png_ptr))) { | 
| return false; | 
| } | 
| @@ -724,11 +767,6 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 
| } | 
| SkAutoLockPixels alp(decodedBitmap); | 
|  | 
| -    /* Add filler (or alpha) byte (before/after each RGB triplet) */ | 
| -    if (colorType == PNG_COLOR_TYPE_RGB || colorType == PNG_COLOR_TYPE_GRAY) { | 
| -        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER); | 
| -    } | 
| - | 
| /* Turn on interlace handling.  REQUIRED if you are not using | 
| * png_read_image().  To see how to handle interlacing passes, | 
| * see the png_read_row() method below: | 
| @@ -752,7 +790,12 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 
|  | 
| int actualTop = rect.fTop; | 
|  | 
| -    if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) { | 
| +    if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config) | 
| +        && 1 == sampleSize) { | 
| +        // A8 is only allowed if the original was GRAY. | 
| +        SkASSERT(config != SkBitmap::kA8_Config | 
| +                 || PNG_COLOR_TYPE_GRAY == colorType); | 
| + | 
| for (int i = 0; i < number_passes; i++) { | 
| png_configure_decoder(png_ptr, &actualTop, i); | 
| for (int j = 0; j < rect.fTop - actualTop; j++) { | 
| @@ -772,6 +815,11 @@ bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) { | 
| if (colorTable != NULL) { | 
| sc = SkScaledBitmapSampler::kIndex; | 
| srcBytesPerPixel = 1; | 
| +        } else if (SkBitmap::kA8_Config == config) { | 
| +            // A8 is only allowed if the original was GRAY. | 
| +            SkASSERT(PNG_COLOR_TYPE_GRAY == colorType); | 
| +            sc = SkScaledBitmapSampler::kGray; | 
| +            srcBytesPerPixel = 1; | 
| } else if (hasAlpha) { | 
| sc = SkScaledBitmapSampler::kRGBA; | 
| } else { | 
|  |