gfx/skia/trunk/src/images/SkImageDecoder_libpng.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/skia/trunk/src/images/SkImageDecoder_libpng.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1296 @@
     1.4 +
     1.5 +/*
     1.6 + * Copyright 2006 The Android Open Source Project
     1.7 + *
     1.8 + * Use of this source code is governed by a BSD-style license that can be
     1.9 + * found in the LICENSE file.
    1.10 + */
    1.11 +
    1.12 +
    1.13 +#include "SkImageDecoder.h"
    1.14 +#include "SkImageEncoder.h"
    1.15 +#include "SkColor.h"
    1.16 +#include "SkColorPriv.h"
    1.17 +#include "SkDither.h"
    1.18 +#include "SkMath.h"
    1.19 +#include "SkRTConf.h"
    1.20 +#include "SkScaledBitmapSampler.h"
    1.21 +#include "SkStream.h"
    1.22 +#include "SkTemplates.h"
    1.23 +#include "SkUtils.h"
    1.24 +#include "transform_scanline.h"
    1.25 +extern "C" {
    1.26 +#include "png.h"
    1.27 +}
    1.28 +
    1.29 +/* These were dropped in libpng >= 1.4 */
    1.30 +#ifndef png_infopp_NULL
    1.31 +#define png_infopp_NULL NULL
    1.32 +#endif
    1.33 +
    1.34 +#ifndef png_bytepp_NULL
    1.35 +#define png_bytepp_NULL NULL
    1.36 +#endif
    1.37 +
    1.38 +#ifndef int_p_NULL
    1.39 +#define int_p_NULL NULL
    1.40 +#endif
    1.41 +
    1.42 +#ifndef png_flush_ptr_NULL
    1.43 +#define png_flush_ptr_NULL NULL
    1.44 +#endif
    1.45 +
    1.46 +#if defined(SK_DEBUG)
    1.47 +#define DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS false
    1.48 +#else  // !defined(SK_DEBUG)
    1.49 +#define DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS true
    1.50 +#endif  // defined(SK_DEBUG)
    1.51 +SK_CONF_DECLARE(bool, c_suppressPNGImageDecoderWarnings,
    1.52 +                "images.png.suppressDecoderWarnings",
    1.53 +                DEFAULT_FOR_SUPPRESS_PNG_IMAGE_DECODER_WARNINGS,
    1.54 +                "Suppress most PNG warnings when calling image decode "
    1.55 +                "functions.");
    1.56 +
    1.57 +
    1.58 +
    1.59 +class SkPNGImageIndex {
    1.60 +public:
    1.61 +    SkPNGImageIndex(SkStreamRewindable* stream, png_structp png_ptr, png_infop info_ptr)
    1.62 +        : fStream(stream)
    1.63 +        , fPng_ptr(png_ptr)
    1.64 +        , fInfo_ptr(info_ptr)
    1.65 +        , fConfig(SkBitmap::kNo_Config) {
    1.66 +        SkASSERT(stream != NULL);
    1.67 +        stream->ref();
    1.68 +    }
    1.69 +    ~SkPNGImageIndex() {
    1.70 +        if (NULL != fPng_ptr) {
    1.71 +            png_destroy_read_struct(&fPng_ptr, &fInfo_ptr, png_infopp_NULL);
    1.72 +        }
    1.73 +    }
    1.74 +
    1.75 +    SkAutoTUnref<SkStreamRewindable>    fStream;
    1.76 +    png_structp                         fPng_ptr;
    1.77 +    png_infop                           fInfo_ptr;
    1.78 +    SkBitmap::Config                    fConfig;
    1.79 +};
    1.80 +
    1.81 +class SkPNGImageDecoder : public SkImageDecoder {
    1.82 +public:
    1.83 +    SkPNGImageDecoder() {
    1.84 +        fImageIndex = NULL;
    1.85 +    }
    1.86 +    virtual Format getFormat() const SK_OVERRIDE {
    1.87 +        return kPNG_Format;
    1.88 +    }
    1.89 +
    1.90 +    virtual ~SkPNGImageDecoder() {
    1.91 +        SkDELETE(fImageIndex);
    1.92 +    }
    1.93 +
    1.94 +protected:
    1.95 +#ifdef SK_BUILD_FOR_ANDROID
    1.96 +    virtual bool onBuildTileIndex(SkStreamRewindable *stream, int *width, int *height) SK_OVERRIDE;
    1.97 +    virtual bool onDecodeSubset(SkBitmap* bitmap, const SkIRect& region) SK_OVERRIDE;
    1.98 +#endif
    1.99 +    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode) SK_OVERRIDE;
   1.100 +
   1.101 +private:
   1.102 +    SkPNGImageIndex* fImageIndex;
   1.103 +
   1.104 +    bool onDecodeInit(SkStream* stream, png_structp *png_ptrp, png_infop *info_ptrp);
   1.105 +    bool decodePalette(png_structp png_ptr, png_infop info_ptr,
   1.106 +                       bool * SK_RESTRICT hasAlphap, bool *reallyHasAlphap,
   1.107 +                       SkColorTable **colorTablep);
   1.108 +    bool getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
   1.109 +                         SkBitmap::Config *config, bool *hasAlpha,
   1.110 +                         SkPMColor *theTranspColor);
   1.111 +
   1.112 +    typedef SkImageDecoder INHERITED;
   1.113 +};
   1.114 +
   1.115 +#ifndef png_jmpbuf
   1.116 +#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
   1.117 +#endif
   1.118 +
   1.119 +#define PNG_BYTES_TO_CHECK 4
   1.120 +
   1.121 +/* Automatically clean up after throwing an exception */
   1.122 +struct PNGAutoClean {
   1.123 +    PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
   1.124 +    ~PNGAutoClean() {
   1.125 +        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
   1.126 +    }
   1.127 +private:
   1.128 +    png_structp png_ptr;
   1.129 +    png_infop info_ptr;
   1.130 +};
   1.131 +
   1.132 +static void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
   1.133 +    SkStream* sk_stream = (SkStream*) png_get_io_ptr(png_ptr);
   1.134 +    size_t bytes = sk_stream->read(data, length);
   1.135 +    if (bytes != length) {
   1.136 +        png_error(png_ptr, "Read Error!");
   1.137 +    }
   1.138 +}
   1.139 +
   1.140 +#ifdef SK_BUILD_FOR_ANDROID
   1.141 +static void sk_seek_fn(png_structp png_ptr, png_uint_32 offset) {
   1.142 +    SkStreamRewindable* sk_stream = (SkStreamRewindable*) png_get_io_ptr(png_ptr);
   1.143 +    if (!sk_stream->rewind()) {
   1.144 +        png_error(png_ptr, "Failed to rewind stream!");
   1.145 +    }
   1.146 +    (void)sk_stream->skip(offset);
   1.147 +}
   1.148 +#endif
   1.149 +
   1.150 +static int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
   1.151 +    SkImageDecoder::Peeker* peeker =
   1.152 +                    (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
   1.153 +    // peek() returning true means continue decoding
   1.154 +    return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
   1.155 +            1 : -1;
   1.156 +}
   1.157 +
   1.158 +static void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
   1.159 +    SkDEBUGF(("------ png error %s\n", msg));
   1.160 +    longjmp(png_jmpbuf(png_ptr), 1);
   1.161 +}
   1.162 +
   1.163 +static void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
   1.164 +    for (int i = 0; i < count; i++) {
   1.165 +        uint8_t* tmp = storage;
   1.166 +        png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
   1.167 +    }
   1.168 +}
   1.169 +
   1.170 +static bool pos_le(int value, int max) {
   1.171 +    return value > 0 && value <= max;
   1.172 +}
   1.173 +
   1.174 +static bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
   1.175 +    SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
   1.176 +
   1.177 +    bool reallyHasAlpha = false;
   1.178 +
   1.179 +    for (int y = bm->height() - 1; y >= 0; --y) {
   1.180 +        SkPMColor* p = bm->getAddr32(0, y);
   1.181 +        for (int x = bm->width() - 1; x >= 0; --x) {
   1.182 +            if (match == *p) {
   1.183 +                *p = 0;
   1.184 +                reallyHasAlpha = true;
   1.185 +            }
   1.186 +            p += 1;
   1.187 +        }
   1.188 +    }
   1.189 +    return reallyHasAlpha;
   1.190 +}
   1.191 +
   1.192 +static bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig,
   1.193 +                                      bool srcHasAlpha) {
   1.194 +    switch (dstConfig) {
   1.195 +        case SkBitmap::kARGB_8888_Config:
   1.196 +        case SkBitmap::kARGB_4444_Config:
   1.197 +            return true;
   1.198 +        case SkBitmap::kRGB_565_Config:
   1.199 +            // only return true if the src is opaque (since 565 is opaque)
   1.200 +            return !srcHasAlpha;
   1.201 +        default:
   1.202 +            return false;
   1.203 +    }
   1.204 +}
   1.205 +
   1.206 +// call only if color_type is PALETTE. Returns true if the ctable has alpha
   1.207 +static bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) {
   1.208 +    png_bytep trans;
   1.209 +    int num_trans;
   1.210 +
   1.211 +    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
   1.212 +        png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
   1.213 +        return num_trans > 0;
   1.214 +    }
   1.215 +    return false;
   1.216 +}
   1.217 +
   1.218 +void do_nothing_warning_fn(png_structp, png_const_charp) {
   1.219 +    /* do nothing */
   1.220 +}
   1.221 +
   1.222 +bool SkPNGImageDecoder::onDecodeInit(SkStream* sk_stream, png_structp *png_ptrp,
   1.223 +                                     png_infop *info_ptrp) {
   1.224 +    /* Create and initialize the png_struct with the desired error handler
   1.225 +    * functions.  If you want to use the default stderr and longjump method,
   1.226 +    * you can supply NULL for the last three parameters.  We also supply the
   1.227 +    * the compiler header file version, so that we know if the application
   1.228 +    * was compiled with a compatible version of the library.  */
   1.229 +
   1.230 +    png_error_ptr user_warning_fn =
   1.231 +        (c_suppressPNGImageDecoderWarnings) ? (&do_nothing_warning_fn) : NULL;
   1.232 +    /* NULL means to leave as default library behavior. */
   1.233 +    /* c_suppressPNGImageDecoderWarnings default depends on SK_DEBUG. */
   1.234 +    /* To suppress warnings with a SK_DEBUG binary, set the
   1.235 +     * environment variable "skia_images_png_suppressDecoderWarnings"
   1.236 +     * to "true".  Inside a program that links to skia:
   1.237 +     * SK_CONF_SET("images.png.suppressDecoderWarnings", true); */
   1.238 +
   1.239 +    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
   1.240 +        NULL, sk_error_fn, user_warning_fn);
   1.241 +    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
   1.242 +    if (png_ptr == NULL) {
   1.243 +        return false;
   1.244 +    }
   1.245 +
   1.246 +    *png_ptrp = png_ptr;
   1.247 +
   1.248 +    /* Allocate/initialize the memory for image information. */
   1.249 +    png_infop info_ptr = png_create_info_struct(png_ptr);
   1.250 +    if (info_ptr == NULL) {
   1.251 +        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
   1.252 +        return false;
   1.253 +    }
   1.254 +    *info_ptrp = info_ptr;
   1.255 +
   1.256 +    /* Set error handling if you are using the setjmp/longjmp method (this is
   1.257 +    * the normal method of doing things with libpng).  REQUIRED unless you
   1.258 +    * set up your own error handlers in the png_create_read_struct() earlier.
   1.259 +    */
   1.260 +    if (setjmp(png_jmpbuf(png_ptr))) {
   1.261 +        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
   1.262 +        return false;
   1.263 +    }
   1.264 +
   1.265 +    /* If you are using replacement read functions, instead of calling
   1.266 +    * png_init_io() here you would call:
   1.267 +    */
   1.268 +    png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
   1.269 +#ifdef SK_BUILD_FOR_ANDROID
   1.270 +    png_set_seek_fn(png_ptr, sk_seek_fn);
   1.271 +#endif
   1.272 +    /* where user_io_ptr is a structure you want available to the callbacks */
   1.273 +    /* If we have already read some of the signature */
   1.274 +//  png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
   1.275 +
   1.276 +    // hookup our peeker so we can see any user-chunks the caller may be interested in
   1.277 +    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
   1.278 +    if (this->getPeeker()) {
   1.279 +        png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
   1.280 +    }
   1.281 +
   1.282 +    /* The call to png_read_info() gives us all of the information from the
   1.283 +    * PNG file before the first IDAT (image data chunk). */
   1.284 +    png_read_info(png_ptr, info_ptr);
   1.285 +    png_uint_32 origWidth, origHeight;
   1.286 +    int bitDepth, colorType;
   1.287 +    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
   1.288 +                 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
   1.289 +
   1.290 +    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
   1.291 +    if (bitDepth == 16) {
   1.292 +        png_set_strip_16(png_ptr);
   1.293 +    }
   1.294 +    /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
   1.295 +     * byte into separate bytes (useful for paletted and grayscale images). */
   1.296 +    if (bitDepth < 8) {
   1.297 +        png_set_packing(png_ptr);
   1.298 +    }
   1.299 +    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
   1.300 +    if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8) {
   1.301 +        png_set_expand_gray_1_2_4_to_8(png_ptr);
   1.302 +    }
   1.303 +
   1.304 +    return true;
   1.305 +}
   1.306 +
   1.307 +bool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
   1.308 +                                 Mode mode) {
   1.309 +    png_structp png_ptr;
   1.310 +    png_infop info_ptr;
   1.311 +
   1.312 +    if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
   1.313 +        return false;
   1.314 +    }
   1.315 +
   1.316 +    PNGAutoClean autoClean(png_ptr, info_ptr);
   1.317 +
   1.318 +    if (setjmp(png_jmpbuf(png_ptr))) {
   1.319 +        return false;
   1.320 +    }
   1.321 +
   1.322 +    png_uint_32 origWidth, origHeight;
   1.323 +    int bitDepth, colorType, interlaceType;
   1.324 +    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
   1.325 +                 &colorType, &interlaceType, int_p_NULL, int_p_NULL);
   1.326 +
   1.327 +    SkBitmap::Config    config;
   1.328 +    bool                hasAlpha = false;
   1.329 +    SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
   1.330 +
   1.331 +    if (!this->getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &theTranspColor)) {
   1.332 +        return false;
   1.333 +    }
   1.334 +
   1.335 +    const int sampleSize = this->getSampleSize();
   1.336 +    SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
   1.337 +    decodedBitmap->setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
   1.338 +
   1.339 +    // we should communicate alphaType, even if we early-return in bounds-only-mode.
   1.340 +    if (this->getRequireUnpremultipliedColors()) {
   1.341 +        decodedBitmap->setAlphaType(kUnpremul_SkAlphaType);
   1.342 +    }
   1.343 +
   1.344 +    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
   1.345 +        return true;
   1.346 +    }
   1.347 +
   1.348 +    // from here down we are concerned with colortables and pixels
   1.349 +
   1.350 +    // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
   1.351 +    // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
   1.352 +    // draw lots faster if we can flag the bitmap has being opaque
   1.353 +    bool reallyHasAlpha = false;
   1.354 +    SkColorTable* colorTable = NULL;
   1.355 +
   1.356 +    if (colorType == PNG_COLOR_TYPE_PALETTE) {
   1.357 +        decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable);
   1.358 +    }
   1.359 +
   1.360 +    SkAutoUnref aur(colorTable);
   1.361 +
   1.362 +    if (!this->allocPixelRef(decodedBitmap,
   1.363 +                             SkBitmap::kIndex8_Config == config ? colorTable : NULL)) {
   1.364 +        return false;
   1.365 +    }
   1.366 +
   1.367 +    SkAutoLockPixels alp(*decodedBitmap);
   1.368 +
   1.369 +    /* Turn on interlace handling.  REQUIRED if you are not using
   1.370 +    *  png_read_image().  To see how to handle interlacing passes,
   1.371 +    *  see the png_read_row() method below:
   1.372 +    */
   1.373 +    const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ?
   1.374 +                              png_set_interlace_handling(png_ptr) : 1;
   1.375 +
   1.376 +    /* Optional call to gamma correct and add the background to the palette
   1.377 +    *  and update info structure.  REQUIRED if you are expecting libpng to
   1.378 +    *  update the palette for you (ie you selected such a transform above).
   1.379 +    */
   1.380 +    png_read_update_info(png_ptr, info_ptr);
   1.381 +
   1.382 +    if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config)
   1.383 +        && 1 == sampleSize) {
   1.384 +        if (SkBitmap::kA8_Config == config) {
   1.385 +            // For an A8 bitmap, we assume there is an alpha for speed. It is
   1.386 +            // possible the bitmap is opaque, but that is an unlikely use case
   1.387 +            // since it would not be very interesting.
   1.388 +            reallyHasAlpha = true;
   1.389 +            // A8 is only allowed if the original was GRAY.
   1.390 +            SkASSERT(PNG_COLOR_TYPE_GRAY == colorType);
   1.391 +        }
   1.392 +        for (int i = 0; i < number_passes; i++) {
   1.393 +            for (png_uint_32 y = 0; y < origHeight; y++) {
   1.394 +                uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
   1.395 +                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
   1.396 +            }
   1.397 +        }
   1.398 +    } else {
   1.399 +        SkScaledBitmapSampler::SrcConfig sc;
   1.400 +        int srcBytesPerPixel = 4;
   1.401 +
   1.402 +        if (colorTable != NULL) {
   1.403 +            sc = SkScaledBitmapSampler::kIndex;
   1.404 +            srcBytesPerPixel = 1;
   1.405 +        } else if (SkBitmap::kA8_Config == config) {
   1.406 +            // A8 is only allowed if the original was GRAY.
   1.407 +            SkASSERT(PNG_COLOR_TYPE_GRAY == colorType);
   1.408 +            sc = SkScaledBitmapSampler::kGray;
   1.409 +            srcBytesPerPixel = 1;
   1.410 +        } else if (hasAlpha) {
   1.411 +            sc = SkScaledBitmapSampler::kRGBA;
   1.412 +        } else {
   1.413 +            sc = SkScaledBitmapSampler::kRGBX;
   1.414 +        }
   1.415 +
   1.416 +        /*  We have to pass the colortable explicitly, since we may have one
   1.417 +            even if our decodedBitmap doesn't, due to the request that we
   1.418 +            upscale png's palette to a direct model
   1.419 +         */
   1.420 +        SkAutoLockColors ctLock(colorTable);
   1.421 +        if (!sampler.begin(decodedBitmap, sc, *this, ctLock.colors())) {
   1.422 +            return false;
   1.423 +        }
   1.424 +        const int height = decodedBitmap->height();
   1.425 +
   1.426 +        if (number_passes > 1) {
   1.427 +            SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
   1.428 +            uint8_t* base = (uint8_t*)storage.get();
   1.429 +            size_t rowBytes = origWidth * srcBytesPerPixel;
   1.430 +
   1.431 +            for (int i = 0; i < number_passes; i++) {
   1.432 +                uint8_t* row = base;
   1.433 +                for (png_uint_32 y = 0; y < origHeight; y++) {
   1.434 +                    uint8_t* bmRow = row;
   1.435 +                    png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
   1.436 +                    row += rowBytes;
   1.437 +                }
   1.438 +            }
   1.439 +            // now sample it
   1.440 +            base += sampler.srcY0() * rowBytes;
   1.441 +            for (int y = 0; y < height; y++) {
   1.442 +                reallyHasAlpha |= sampler.next(base);
   1.443 +                base += sampler.srcDY() * rowBytes;
   1.444 +            }
   1.445 +        } else {
   1.446 +            SkAutoMalloc storage(origWidth * srcBytesPerPixel);
   1.447 +            uint8_t* srcRow = (uint8_t*)storage.get();
   1.448 +            skip_src_rows(png_ptr, srcRow, sampler.srcY0());
   1.449 +
   1.450 +            for (int y = 0; y < height; y++) {
   1.451 +                uint8_t* tmp = srcRow;
   1.452 +                png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
   1.453 +                reallyHasAlpha |= sampler.next(srcRow);
   1.454 +                if (y < height - 1) {
   1.455 +                    skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
   1.456 +                }
   1.457 +            }
   1.458 +
   1.459 +            // skip the rest of the rows (if any)
   1.460 +            png_uint_32 read = (height - 1) * sampler.srcDY() +
   1.461 +                               sampler.srcY0() + 1;
   1.462 +            SkASSERT(read <= origHeight);
   1.463 +            skip_src_rows(png_ptr, srcRow, origHeight - read);
   1.464 +        }
   1.465 +    }
   1.466 +
   1.467 +    /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
   1.468 +    png_read_end(png_ptr, info_ptr);
   1.469 +
   1.470 +    if (0 != theTranspColor) {
   1.471 +        reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
   1.472 +    }
   1.473 +    if (reallyHasAlpha && this->getRequireUnpremultipliedColors()) {
   1.474 +        switch (decodedBitmap->config()) {
   1.475 +            case SkBitmap::kIndex8_Config:
   1.476 +                // Fall through.
   1.477 +            case SkBitmap::kARGB_4444_Config:
   1.478 +                // We have chosen not to support unpremul for these configs.
   1.479 +                return false;
   1.480 +            default: {
   1.481 +                // Fall through to finish the decode. This config either
   1.482 +                // supports unpremul or it is irrelevant because it has no
   1.483 +                // alpha (or only alpha).
   1.484 +                // These brackets prevent a warning.
   1.485 +            }
   1.486 +        }
   1.487 +    }
   1.488 +
   1.489 +    if (!reallyHasAlpha) {
   1.490 +        decodedBitmap->setAlphaType(kOpaque_SkAlphaType);
   1.491 +    }
   1.492 +    return true;
   1.493 +}
   1.494 +
   1.495 +
   1.496 +
   1.497 +bool SkPNGImageDecoder::getBitmapConfig(png_structp png_ptr, png_infop info_ptr,
   1.498 +                                        SkBitmap::Config* SK_RESTRICT configp,
   1.499 +                                        bool* SK_RESTRICT hasAlphap,
   1.500 +                                        SkPMColor* SK_RESTRICT theTranspColorp) {
   1.501 +    png_uint_32 origWidth, origHeight;
   1.502 +    int bitDepth, colorType;
   1.503 +    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
   1.504 +                 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
   1.505 +
   1.506 +    // check for sBIT chunk data, in case we should disable dithering because
   1.507 +    // our data is not truely 8bits per component
   1.508 +    png_color_8p sig_bit;
   1.509 +    if (this->getDitherImage() && png_get_sBIT(png_ptr, info_ptr, &sig_bit)) {
   1.510 +#if 0
   1.511 +        SkDebugf("----- sBIT %d %d %d %d\n", sig_bit->red, sig_bit->green,
   1.512 +                 sig_bit->blue, sig_bit->alpha);
   1.513 +#endif
   1.514 +        // 0 seems to indicate no information available
   1.515 +        if (pos_le(sig_bit->red, SK_R16_BITS) &&
   1.516 +            pos_le(sig_bit->green, SK_G16_BITS) &&
   1.517 +            pos_le(sig_bit->blue, SK_B16_BITS)) {
   1.518 +            this->setDitherImage(false);
   1.519 +        }
   1.520 +    }
   1.521 +
   1.522 +    if (colorType == PNG_COLOR_TYPE_PALETTE) {
   1.523 +        bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
   1.524 +        *configp = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
   1.525 +        // now see if we can upscale to their requested config
   1.526 +        if (!canUpscalePaletteToConfig(*configp, paletteHasAlpha)) {
   1.527 +            *configp = SkBitmap::kIndex8_Config;
   1.528 +        }
   1.529 +    } else {
   1.530 +        png_color_16p transpColor = NULL;
   1.531 +        int numTransp = 0;
   1.532 +
   1.533 +        png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
   1.534 +
   1.535 +        bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
   1.536 +
   1.537 +        if (valid && numTransp == 1 && transpColor != NULL) {
   1.538 +            /*  Compute our transparent color, which we'll match against later.
   1.539 +                We don't really handle 16bit components properly here, since we
   1.540 +                do our compare *after* the values have been knocked down to 8bit
   1.541 +                which means we will find more matches than we should. The real
   1.542 +                fix seems to be to see the actual 16bit components, do the
   1.543 +                compare, and then knock it down to 8bits ourselves.
   1.544 +            */
   1.545 +            if (colorType & PNG_COLOR_MASK_COLOR) {
   1.546 +                if (16 == bitDepth) {
   1.547 +                    *theTranspColorp = SkPackARGB32(0xFF, transpColor->red >> 8,
   1.548 +                                                    transpColor->green >> 8,
   1.549 +                                                    transpColor->blue >> 8);
   1.550 +                } else {
   1.551 +                    /* We apply the mask because in a very small
   1.552 +                       number of corrupt PNGs, (transpColor->red > 255)
   1.553 +                       and (bitDepth == 8), for certain versions of libpng. */
   1.554 +                    *theTranspColorp = SkPackARGB32(0xFF,
   1.555 +                                                    0xFF & (transpColor->red),
   1.556 +                                                    0xFF & (transpColor->green),
   1.557 +                                                    0xFF & (transpColor->blue));
   1.558 +                }
   1.559 +            } else {    // gray
   1.560 +                if (16 == bitDepth) {
   1.561 +                    *theTranspColorp = SkPackARGB32(0xFF, transpColor->gray >> 8,
   1.562 +                                                    transpColor->gray >> 8,
   1.563 +                                                    transpColor->gray >> 8);
   1.564 +                } else {
   1.565 +                    /* We apply the mask because in a very small
   1.566 +                       number of corrupt PNGs, (transpColor->red >
   1.567 +                       255) and (bitDepth == 8), for certain versions
   1.568 +                       of libpng.  For safety we assume the same could
   1.569 +                       happen with a grayscale PNG.  */
   1.570 +                    *theTranspColorp = SkPackARGB32(0xFF,
   1.571 +                                                    0xFF & (transpColor->gray),
   1.572 +                                                    0xFF & (transpColor->gray),
   1.573 +                                                    0xFF & (transpColor->gray));
   1.574 +                }
   1.575 +            }
   1.576 +        }
   1.577 +
   1.578 +        if (valid ||
   1.579 +            PNG_COLOR_TYPE_RGB_ALPHA == colorType ||
   1.580 +            PNG_COLOR_TYPE_GRAY_ALPHA == colorType) {
   1.581 +            *hasAlphap = true;
   1.582 +        }
   1.583 +
   1.584 +        SrcDepth srcDepth = k32Bit_SrcDepth;
   1.585 +        if (PNG_COLOR_TYPE_GRAY == colorType) {
   1.586 +            srcDepth = k8BitGray_SrcDepth;
   1.587 +            // Remove this assert, which fails on desk_pokemonwiki.skp
   1.588 +            //SkASSERT(!*hasAlphap);
   1.589 +        }
   1.590 +
   1.591 +        *configp = this->getPrefConfig(srcDepth, *hasAlphap);
   1.592 +        // now match the request against our capabilities
   1.593 +        if (*hasAlphap) {
   1.594 +            if (*configp != SkBitmap::kARGB_4444_Config) {
   1.595 +                *configp = SkBitmap::kARGB_8888_Config;
   1.596 +            }
   1.597 +        } else {
   1.598 +            if (SkBitmap::kA8_Config == *configp) {
   1.599 +                if (k8BitGray_SrcDepth != srcDepth) {
   1.600 +                    // Converting a non grayscale image to A8 is not currently supported.
   1.601 +                    *configp = SkBitmap::kARGB_8888_Config;
   1.602 +                }
   1.603 +            } else if (*configp != SkBitmap::kRGB_565_Config &&
   1.604 +                       *configp != SkBitmap::kARGB_4444_Config) {
   1.605 +                *configp = SkBitmap::kARGB_8888_Config;
   1.606 +            }
   1.607 +        }
   1.608 +    }
   1.609 +
   1.610 +    // sanity check for size
   1.611 +    {
   1.612 +        int64_t size = sk_64_mul(origWidth, origHeight);
   1.613 +        // now check that if we are 4-bytes per pixel, we also don't overflow
   1.614 +        if (size < 0 || size > (0x7FFFFFFF >> 2)) {
   1.615 +            return false;
   1.616 +        }
   1.617 +    }
   1.618 +
   1.619 +    if (!this->chooseFromOneChoice(*configp, origWidth, origHeight)) {
   1.620 +        return false;
   1.621 +    }
   1.622 +
   1.623 +    // If the image has alpha and the decoder wants unpremultiplied
   1.624 +    // colors, the only supported config is 8888.
   1.625 +    if (this->getRequireUnpremultipliedColors() && *hasAlphap) {
   1.626 +        *configp = SkBitmap::kARGB_8888_Config;
   1.627 +    }
   1.628 +
   1.629 +    if (fImageIndex != NULL) {
   1.630 +        if (SkBitmap::kNo_Config == fImageIndex->fConfig) {
   1.631 +            // This is the first time for this subset decode. From now on,
   1.632 +            // all decodes must be in the same config.
   1.633 +            fImageIndex->fConfig = *configp;
   1.634 +        } else if (fImageIndex->fConfig != *configp) {
   1.635 +            // Requesting a different config for a subsequent decode is not
   1.636 +            // supported. Report failure before we make changes to png_ptr.
   1.637 +            return false;
   1.638 +        }
   1.639 +    }
   1.640 +
   1.641 +    bool convertGrayToRGB = PNG_COLOR_TYPE_GRAY == colorType
   1.642 +                            && *configp != SkBitmap::kA8_Config;
   1.643 +
   1.644 +    // Unless the user is requesting A8, convert a grayscale image into RGB.
   1.645 +    // GRAY_ALPHA will always be converted to RGB
   1.646 +    if (convertGrayToRGB || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) {
   1.647 +        png_set_gray_to_rgb(png_ptr);
   1.648 +    }
   1.649 +
   1.650 +    // Add filler (or alpha) byte (after each RGB triplet) if necessary.
   1.651 +    if (colorType == PNG_COLOR_TYPE_RGB || convertGrayToRGB) {
   1.652 +        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
   1.653 +    }
   1.654 +
   1.655 +    return true;
   1.656 +}
   1.657 +
   1.658 +typedef uint32_t (*PackColorProc)(U8CPU a, U8CPU r, U8CPU g, U8CPU b);
   1.659 +
   1.660 +bool SkPNGImageDecoder::decodePalette(png_structp png_ptr, png_infop info_ptr,
   1.661 +                                      bool *hasAlphap, bool *reallyHasAlphap,
   1.662 +                                      SkColorTable **colorTablep) {
   1.663 +    int numPalette;
   1.664 +    png_colorp palette;
   1.665 +    png_bytep trans;
   1.666 +    int numTrans;
   1.667 +
   1.668 +    png_get_PLTE(png_ptr, info_ptr, &palette, &numPalette);
   1.669 +
   1.670 +    /*  BUGGY IMAGE WORKAROUND
   1.671 +
   1.672 +        We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
   1.673 +        which is a problem since we use the byte as an index. To work around this we grow
   1.674 +        the colortable by 1 (if its < 256) and duplicate the last color into that slot.
   1.675 +    */
   1.676 +    int colorCount = numPalette + (numPalette < 256);
   1.677 +    SkPMColor colorStorage[256];    // worst-case storage
   1.678 +    SkPMColor* colorPtr = colorStorage;
   1.679 +
   1.680 +    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
   1.681 +        png_get_tRNS(png_ptr, info_ptr, &trans, &numTrans, NULL);
   1.682 +        *hasAlphap = (numTrans > 0);
   1.683 +    } else {
   1.684 +        numTrans = 0;
   1.685 +    }
   1.686 +
   1.687 +    // check for bad images that might make us crash
   1.688 +    if (numTrans > numPalette) {
   1.689 +        numTrans = numPalette;
   1.690 +    }
   1.691 +
   1.692 +    int index = 0;
   1.693 +    int transLessThanFF = 0;
   1.694 +
   1.695 +    // Choose which function to use to create the color table. If the final destination's
   1.696 +    // config is unpremultiplied, the color table will store unpremultiplied colors.
   1.697 +    PackColorProc proc;
   1.698 +    if (this->getRequireUnpremultipliedColors()) {
   1.699 +        proc = &SkPackARGB32NoCheck;
   1.700 +    } else {
   1.701 +        proc = &SkPreMultiplyARGB;
   1.702 +    }
   1.703 +    for (; index < numTrans; index++) {
   1.704 +        transLessThanFF |= (int)*trans - 0xFF;
   1.705 +        *colorPtr++ = proc(*trans++, palette->red, palette->green, palette->blue);
   1.706 +        palette++;
   1.707 +    }
   1.708 +    bool reallyHasAlpha = (transLessThanFF < 0);
   1.709 +
   1.710 +    for (; index < numPalette; index++) {
   1.711 +        *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
   1.712 +        palette++;
   1.713 +    }
   1.714 +
   1.715 +    // see BUGGY IMAGE WORKAROUND comment above
   1.716 +    if (numPalette < 256) {
   1.717 +        *colorPtr = colorPtr[-1];
   1.718 +    }
   1.719 +
   1.720 +    SkAlphaType alphaType = kOpaque_SkAlphaType;
   1.721 +    if (reallyHasAlpha) {
   1.722 +        if (this->getRequireUnpremultipliedColors()) {
   1.723 +            alphaType = kUnpremul_SkAlphaType;
   1.724 +        } else {
   1.725 +            alphaType = kPremul_SkAlphaType;
   1.726 +        }
   1.727 +    }
   1.728 +
   1.729 +    *colorTablep = SkNEW_ARGS(SkColorTable,
   1.730 +                              (colorStorage, colorCount, alphaType));
   1.731 +    *reallyHasAlphap = reallyHasAlpha;
   1.732 +    return true;
   1.733 +}
   1.734 +
   1.735 +#ifdef SK_BUILD_FOR_ANDROID
   1.736 +
   1.737 +bool SkPNGImageDecoder::onBuildTileIndex(SkStreamRewindable* sk_stream, int *width, int *height) {
   1.738 +    png_structp png_ptr;
   1.739 +    png_infop   info_ptr;
   1.740 +
   1.741 +    if (!onDecodeInit(sk_stream, &png_ptr, &info_ptr)) {
   1.742 +        return false;
   1.743 +    }
   1.744 +
   1.745 +    if (setjmp(png_jmpbuf(png_ptr)) != 0) {
   1.746 +        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
   1.747 +        return false;
   1.748 +    }
   1.749 +
   1.750 +    png_uint_32 origWidth, origHeight;
   1.751 +    int bitDepth, colorType;
   1.752 +    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
   1.753 +                 &colorType, int_p_NULL, int_p_NULL, int_p_NULL);
   1.754 +
   1.755 +    *width = origWidth;
   1.756 +    *height = origHeight;
   1.757 +
   1.758 +    png_build_index(png_ptr);
   1.759 +
   1.760 +    if (fImageIndex) {
   1.761 +        SkDELETE(fImageIndex);
   1.762 +    }
   1.763 +    fImageIndex = SkNEW_ARGS(SkPNGImageIndex, (sk_stream, png_ptr, info_ptr));
   1.764 +
   1.765 +    return true;
   1.766 +}
   1.767 +
   1.768 +bool SkPNGImageDecoder::onDecodeSubset(SkBitmap* bm, const SkIRect& region) {
   1.769 +    if (NULL == fImageIndex) {
   1.770 +        return false;
   1.771 +    }
   1.772 +
   1.773 +    png_structp png_ptr = fImageIndex->fPng_ptr;
   1.774 +    png_infop info_ptr = fImageIndex->fInfo_ptr;
   1.775 +    if (setjmp(png_jmpbuf(png_ptr))) {
   1.776 +        return false;
   1.777 +    }
   1.778 +
   1.779 +    png_uint_32 origWidth, origHeight;
   1.780 +    int bitDepth, colorType, interlaceType;
   1.781 +    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bitDepth,
   1.782 +                 &colorType, &interlaceType, int_p_NULL, int_p_NULL);
   1.783 +
   1.784 +    SkIRect rect = SkIRect::MakeWH(origWidth, origHeight);
   1.785 +
   1.786 +    if (!rect.intersect(region)) {
   1.787 +        // If the requested region is entirely outside the image, just
   1.788 +        // returns false
   1.789 +        return false;
   1.790 +    }
   1.791 +
   1.792 +    SkBitmap::Config    config;
   1.793 +    bool                hasAlpha = false;
   1.794 +    SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
   1.795 +
   1.796 +    if (!this->getBitmapConfig(png_ptr, info_ptr, &config, &hasAlpha, &theTranspColor)) {
   1.797 +        return false;
   1.798 +    }
   1.799 +
   1.800 +    const int sampleSize = this->getSampleSize();
   1.801 +    SkScaledBitmapSampler sampler(origWidth, rect.height(), sampleSize);
   1.802 +
   1.803 +    SkBitmap decodedBitmap;
   1.804 +    decodedBitmap.setConfig(config, sampler.scaledWidth(), sampler.scaledHeight());
   1.805 +
   1.806 +    // from here down we are concerned with colortables and pixels
   1.807 +
   1.808 +    // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
   1.809 +    // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
   1.810 +    // draw lots faster if we can flag the bitmap has being opaque
   1.811 +    bool reallyHasAlpha = false;
   1.812 +    SkColorTable* colorTable = NULL;
   1.813 +
   1.814 +    if (colorType == PNG_COLOR_TYPE_PALETTE) {
   1.815 +        decodePalette(png_ptr, info_ptr, &hasAlpha, &reallyHasAlpha, &colorTable);
   1.816 +    }
   1.817 +
   1.818 +    SkAutoUnref aur(colorTable);
   1.819 +
   1.820 +    // Check ahead of time if the swap(dest, src) is possible.
   1.821 +    // If yes, then we will stick to AllocPixelRef since it's cheaper with the swap happening.
   1.822 +    // If no, then we will use alloc to allocate pixels to prevent garbage collection.
   1.823 +    int w = rect.width() / sampleSize;
   1.824 +    int h = rect.height() / sampleSize;
   1.825 +    const bool swapOnly = (rect == region) && (w == decodedBitmap.width()) &&
   1.826 +                          (h == decodedBitmap.height()) && bm->isNull();
   1.827 +    const bool needColorTable = SkBitmap::kIndex8_Config == config;
   1.828 +    if (swapOnly) {
   1.829 +        if (!this->allocPixelRef(&decodedBitmap, needColorTable ? colorTable : NULL)) {
   1.830 +            return false;
   1.831 +        }
   1.832 +    } else {
   1.833 +        if (!decodedBitmap.allocPixels(NULL, needColorTable ? colorTable : NULL)) {
   1.834 +            return false;
   1.835 +        }
   1.836 +    }
   1.837 +    SkAutoLockPixels alp(decodedBitmap);
   1.838 +
   1.839 +    /* Turn on interlace handling.  REQUIRED if you are not using
   1.840 +    * png_read_image().  To see how to handle interlacing passes,
   1.841 +    * see the png_read_row() method below:
   1.842 +    */
   1.843 +    const int number_passes = (interlaceType != PNG_INTERLACE_NONE) ?
   1.844 +                              png_set_interlace_handling(png_ptr) : 1;
   1.845 +
   1.846 +    /* Optional call to gamma correct and add the background to the palette
   1.847 +    * and update info structure.  REQUIRED if you are expecting libpng to
   1.848 +    * update the palette for you (ie you selected such a transform above).
   1.849 +    */
   1.850 +
   1.851 +    // Direct access to png_ptr fields is deprecated in libpng > 1.2.
   1.852 +#if defined(PNG_1_0_X) || defined (PNG_1_2_X)
   1.853 +    png_ptr->pass = 0;
   1.854 +#else
   1.855 +    // FIXME: This sets pass as desired, but also sets iwidth. Is that ok?
   1.856 +    png_set_interlaced_pass(png_ptr, 0);
   1.857 +#endif
   1.858 +    png_read_update_info(png_ptr, info_ptr);
   1.859 +
   1.860 +    int actualTop = rect.fTop;
   1.861 +
   1.862 +    if ((SkBitmap::kA8_Config == config || SkBitmap::kIndex8_Config == config)
   1.863 +        && 1 == sampleSize) {
   1.864 +        if (SkBitmap::kA8_Config == config) {
   1.865 +            // For an A8 bitmap, we assume there is an alpha for speed. It is
   1.866 +            // possible the bitmap is opaque, but that is an unlikely use case
   1.867 +            // since it would not be very interesting.
   1.868 +            reallyHasAlpha = true;
   1.869 +            // A8 is only allowed if the original was GRAY.
   1.870 +            SkASSERT(PNG_COLOR_TYPE_GRAY == colorType);
   1.871 +        }
   1.872 +
   1.873 +        for (int i = 0; i < number_passes; i++) {
   1.874 +            png_configure_decoder(png_ptr, &actualTop, i);
   1.875 +            for (int j = 0; j < rect.fTop - actualTop; j++) {
   1.876 +                uint8_t* bmRow = decodedBitmap.getAddr8(0, 0);
   1.877 +                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
   1.878 +            }
   1.879 +            png_uint_32 bitmapHeight = (png_uint_32) decodedBitmap.height();
   1.880 +            for (png_uint_32 y = 0; y < bitmapHeight; y++) {
   1.881 +                uint8_t* bmRow = decodedBitmap.getAddr8(0, y);
   1.882 +                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
   1.883 +            }
   1.884 +        }
   1.885 +    } else {
   1.886 +        SkScaledBitmapSampler::SrcConfig sc;
   1.887 +        int srcBytesPerPixel = 4;
   1.888 +
   1.889 +        if (colorTable != NULL) {
   1.890 +            sc = SkScaledBitmapSampler::kIndex;
   1.891 +            srcBytesPerPixel = 1;
   1.892 +        } else if (SkBitmap::kA8_Config == config) {
   1.893 +            // A8 is only allowed if the original was GRAY.
   1.894 +            SkASSERT(PNG_COLOR_TYPE_GRAY == colorType);
   1.895 +            sc = SkScaledBitmapSampler::kGray;
   1.896 +            srcBytesPerPixel = 1;
   1.897 +        } else if (hasAlpha) {
   1.898 +            sc = SkScaledBitmapSampler::kRGBA;
   1.899 +        } else {
   1.900 +            sc = SkScaledBitmapSampler::kRGBX;
   1.901 +        }
   1.902 +
   1.903 +        /*  We have to pass the colortable explicitly, since we may have one
   1.904 +            even if our decodedBitmap doesn't, due to the request that we
   1.905 +            upscale png's palette to a direct model
   1.906 +         */
   1.907 +        SkAutoLockColors ctLock(colorTable);
   1.908 +        if (!sampler.begin(&decodedBitmap, sc, *this, ctLock.colors())) {
   1.909 +            return false;
   1.910 +        }
   1.911 +        const int height = decodedBitmap.height();
   1.912 +
   1.913 +        if (number_passes > 1) {
   1.914 +            SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
   1.915 +            uint8_t* base = (uint8_t*)storage.get();
   1.916 +            size_t rb = origWidth * srcBytesPerPixel;
   1.917 +
   1.918 +            for (int i = 0; i < number_passes; i++) {
   1.919 +                png_configure_decoder(png_ptr, &actualTop, i);
   1.920 +                for (int j = 0; j < rect.fTop - actualTop; j++) {
   1.921 +                    uint8_t* bmRow = (uint8_t*)decodedBitmap.getPixels();
   1.922 +                    png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
   1.923 +                }
   1.924 +                uint8_t* row = base;
   1.925 +                for (int32_t y = 0; y < rect.height(); y++) {
   1.926 +                    uint8_t* bmRow = row;
   1.927 +                    png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
   1.928 +                    row += rb;
   1.929 +                }
   1.930 +            }
   1.931 +            // now sample it
   1.932 +            base += sampler.srcY0() * rb;
   1.933 +            for (int y = 0; y < height; y++) {
   1.934 +                reallyHasAlpha |= sampler.next(base);
   1.935 +                base += sampler.srcDY() * rb;
   1.936 +            }
   1.937 +        } else {
   1.938 +            SkAutoMalloc storage(origWidth * srcBytesPerPixel);
   1.939 +            uint8_t* srcRow = (uint8_t*)storage.get();
   1.940 +
   1.941 +            png_configure_decoder(png_ptr, &actualTop, 0);
   1.942 +            skip_src_rows(png_ptr, srcRow, sampler.srcY0());
   1.943 +
   1.944 +            for (int i = 0; i < rect.fTop - actualTop; i++) {
   1.945 +                uint8_t* bmRow = (uint8_t*)decodedBitmap.getPixels();
   1.946 +                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
   1.947 +            }
   1.948 +            for (int y = 0; y < height; y++) {
   1.949 +                uint8_t* tmp = srcRow;
   1.950 +                png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
   1.951 +                reallyHasAlpha |= sampler.next(srcRow);
   1.952 +                if (y < height - 1) {
   1.953 +                    skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
   1.954 +                }
   1.955 +            }
   1.956 +        }
   1.957 +    }
   1.958 +
   1.959 +    if (0 != theTranspColor) {
   1.960 +        reallyHasAlpha |= substituteTranspColor(&decodedBitmap, theTranspColor);
   1.961 +    }
   1.962 +    if (reallyHasAlpha && this->getRequireUnpremultipliedColors()) {
   1.963 +        switch (decodedBitmap.config()) {
   1.964 +            case SkBitmap::kIndex8_Config:
   1.965 +                // Fall through.
   1.966 +            case SkBitmap::kARGB_4444_Config:
   1.967 +                // We have chosen not to support unpremul for these configs.
   1.968 +                return false;
   1.969 +            default: {
   1.970 +                // Fall through to finish the decode. This config either
   1.971 +                // supports unpremul or it is irrelevant because it has no
   1.972 +                // alpha (or only alpha).
   1.973 +                // These brackets prevent a warning.
   1.974 +            }
   1.975 +        }
   1.976 +    }
   1.977 +    SkAlphaType alphaType = kOpaque_SkAlphaType;
   1.978 +    if (reallyHasAlpha) {
   1.979 +        if (this->getRequireUnpremultipliedColors()) {
   1.980 +            alphaType = kUnpremul_SkAlphaType;
   1.981 +        } else {
   1.982 +            alphaType = kPremul_SkAlphaType;
   1.983 +        }
   1.984 +    }
   1.985 +    decodedBitmap.setAlphaType(alphaType);
   1.986 +
   1.987 +    if (swapOnly) {
   1.988 +        bm->swap(decodedBitmap);
   1.989 +        return true;
   1.990 +    }
   1.991 +    return this->cropBitmap(bm, &decodedBitmap, sampleSize, region.x(), region.y(),
   1.992 +                            region.width(), region.height(), 0, rect.y());
   1.993 +}
   1.994 +#endif
   1.995 +
   1.996 +///////////////////////////////////////////////////////////////////////////////
   1.997 +
   1.998 +#include "SkColorPriv.h"
   1.999 +#include "SkUnPreMultiply.h"
  1.1000 +
  1.1001 +static void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
  1.1002 +    SkWStream* sk_stream = (SkWStream*)png_get_io_ptr(png_ptr);
  1.1003 +    if (!sk_stream->write(data, len)) {
  1.1004 +        png_error(png_ptr, "sk_write_fn Error!");
  1.1005 +    }
  1.1006 +}
  1.1007 +
  1.1008 +static transform_scanline_proc choose_proc(SkBitmap::Config config,
  1.1009 +                                           bool hasAlpha) {
  1.1010 +    // we don't care about search on alpha if we're kIndex8, since only the
  1.1011 +    // colortable packing cares about that distinction, not the pixels
  1.1012 +    if (SkBitmap::kIndex8_Config == config) {
  1.1013 +        hasAlpha = false;   // we store false in the table entries for kIndex8
  1.1014 +    }
  1.1015 +
  1.1016 +    static const struct {
  1.1017 +        SkBitmap::Config        fConfig;
  1.1018 +        bool                    fHasAlpha;
  1.1019 +        transform_scanline_proc fProc;
  1.1020 +    } gMap[] = {
  1.1021 +        { SkBitmap::kRGB_565_Config,    false,  transform_scanline_565 },
  1.1022 +        { SkBitmap::kARGB_8888_Config,  false,  transform_scanline_888 },
  1.1023 +        { SkBitmap::kARGB_8888_Config,  true,   transform_scanline_8888 },
  1.1024 +        { SkBitmap::kARGB_4444_Config,  false,  transform_scanline_444 },
  1.1025 +        { SkBitmap::kARGB_4444_Config,  true,   transform_scanline_4444 },
  1.1026 +        { SkBitmap::kIndex8_Config,     false,  transform_scanline_memcpy },
  1.1027 +    };
  1.1028 +
  1.1029 +    for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
  1.1030 +        if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) {
  1.1031 +            return gMap[i].fProc;
  1.1032 +        }
  1.1033 +    }
  1.1034 +    sk_throw();
  1.1035 +    return NULL;
  1.1036 +}
  1.1037 +
  1.1038 +// return the minimum legal bitdepth (by png standards) for this many colortable
  1.1039 +// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
  1.1040 +// we can use fewer bits per in png
  1.1041 +static int computeBitDepth(int colorCount) {
  1.1042 +#if 0
  1.1043 +    int bits = SkNextLog2(colorCount);
  1.1044 +    SkASSERT(bits >= 1 && bits <= 8);
  1.1045 +    // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
  1.1046 +    return SkNextPow2(bits);
  1.1047 +#else
  1.1048 +    // for the moment, we don't know how to pack bitdepth < 8
  1.1049 +    return 8;
  1.1050 +#endif
  1.1051 +}
  1.1052 +
  1.1053 +/*  Pack palette[] with the corresponding colors, and if hasAlpha is true, also
  1.1054 +    pack trans[] and return the number of trans[] entries written. If hasAlpha
  1.1055 +    is false, the return value will always be 0.
  1.1056 +
  1.1057 +    Note: this routine takes care of unpremultiplying the RGB values when we
  1.1058 +    have alpha in the colortable, since png doesn't support premul colors
  1.1059 +*/
  1.1060 +static inline int pack_palette(SkColorTable* ctable,
  1.1061 +                               png_color* SK_RESTRICT palette,
  1.1062 +                               png_byte* SK_RESTRICT trans, bool hasAlpha) {
  1.1063 +    SkAutoLockColors alc(ctable);
  1.1064 +    const SkPMColor* SK_RESTRICT colors = alc.colors();
  1.1065 +    const int ctCount = ctable->count();
  1.1066 +    int i, num_trans = 0;
  1.1067 +
  1.1068 +    if (hasAlpha) {
  1.1069 +        /*  first see if we have some number of fully opaque at the end of the
  1.1070 +            ctable. PNG allows num_trans < num_palette, but all of the trans
  1.1071 +            entries must come first in the palette. If I was smarter, I'd
  1.1072 +            reorder the indices and ctable so that all non-opaque colors came
  1.1073 +            first in the palette. But, since that would slow down the encode,
  1.1074 +            I'm leaving the indices and ctable order as is, and just looking
  1.1075 +            at the tail of the ctable for opaqueness.
  1.1076 +        */
  1.1077 +        num_trans = ctCount;
  1.1078 +        for (i = ctCount - 1; i >= 0; --i) {
  1.1079 +            if (SkGetPackedA32(colors[i]) != 0xFF) {
  1.1080 +                break;
  1.1081 +            }
  1.1082 +            num_trans -= 1;
  1.1083 +        }
  1.1084 +
  1.1085 +        const SkUnPreMultiply::Scale* SK_RESTRICT table =
  1.1086 +                                            SkUnPreMultiply::GetScaleTable();
  1.1087 +
  1.1088 +        for (i = 0; i < num_trans; i++) {
  1.1089 +            const SkPMColor c = *colors++;
  1.1090 +            const unsigned a = SkGetPackedA32(c);
  1.1091 +            const SkUnPreMultiply::Scale s = table[a];
  1.1092 +            trans[i] = a;
  1.1093 +            palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
  1.1094 +            palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
  1.1095 +            palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
  1.1096 +        }
  1.1097 +        // now fall out of this if-block to use common code for the trailing
  1.1098 +        // opaque entries
  1.1099 +    }
  1.1100 +
  1.1101 +    // these (remaining) entries are opaque
  1.1102 +    for (i = num_trans; i < ctCount; i++) {
  1.1103 +        SkPMColor c = *colors++;
  1.1104 +        palette[i].red = SkGetPackedR32(c);
  1.1105 +        palette[i].green = SkGetPackedG32(c);
  1.1106 +        palette[i].blue = SkGetPackedB32(c);
  1.1107 +    }
  1.1108 +    return num_trans;
  1.1109 +}
  1.1110 +
  1.1111 +class SkPNGImageEncoder : public SkImageEncoder {
  1.1112 +protected:
  1.1113 +    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality) SK_OVERRIDE;
  1.1114 +private:
  1.1115 +    bool doEncode(SkWStream* stream, const SkBitmap& bm,
  1.1116 +                  const bool& hasAlpha, int colorType,
  1.1117 +                  int bitDepth, SkBitmap::Config config,
  1.1118 +                  png_color_8& sig_bit);
  1.1119 +
  1.1120 +    typedef SkImageEncoder INHERITED;
  1.1121 +};
  1.1122 +
  1.1123 +bool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
  1.1124 +                                 int /*quality*/) {
  1.1125 +    SkBitmap::Config config = bitmap.config();
  1.1126 +
  1.1127 +    const bool hasAlpha = !bitmap.isOpaque();
  1.1128 +    int colorType = PNG_COLOR_MASK_COLOR;
  1.1129 +    int bitDepth = 8;   // default for color
  1.1130 +    png_color_8 sig_bit;
  1.1131 +
  1.1132 +    switch (config) {
  1.1133 +        case SkBitmap::kIndex8_Config:
  1.1134 +            colorType |= PNG_COLOR_MASK_PALETTE;
  1.1135 +            // fall through to the ARGB_8888 case
  1.1136 +        case SkBitmap::kARGB_8888_Config:
  1.1137 +            sig_bit.red = 8;
  1.1138 +            sig_bit.green = 8;
  1.1139 +            sig_bit.blue = 8;
  1.1140 +            sig_bit.alpha = 8;
  1.1141 +            break;
  1.1142 +        case SkBitmap::kARGB_4444_Config:
  1.1143 +            sig_bit.red = 4;
  1.1144 +            sig_bit.green = 4;
  1.1145 +            sig_bit.blue = 4;
  1.1146 +            sig_bit.alpha = 4;
  1.1147 +            break;
  1.1148 +        case SkBitmap::kRGB_565_Config:
  1.1149 +            sig_bit.red = 5;
  1.1150 +            sig_bit.green = 6;
  1.1151 +            sig_bit.blue = 5;
  1.1152 +            sig_bit.alpha = 0;
  1.1153 +            break;
  1.1154 +        default:
  1.1155 +            return false;
  1.1156 +    }
  1.1157 +
  1.1158 +    if (hasAlpha) {
  1.1159 +        // don't specify alpha if we're a palette, even if our ctable has alpha
  1.1160 +        if (!(colorType & PNG_COLOR_MASK_PALETTE)) {
  1.1161 +            colorType |= PNG_COLOR_MASK_ALPHA;
  1.1162 +        }
  1.1163 +    } else {
  1.1164 +        sig_bit.alpha = 0;
  1.1165 +    }
  1.1166 +
  1.1167 +    SkAutoLockPixels alp(bitmap);
  1.1168 +    // readyToDraw checks for pixels (and colortable if that is required)
  1.1169 +    if (!bitmap.readyToDraw()) {
  1.1170 +        return false;
  1.1171 +    }
  1.1172 +
  1.1173 +    // we must do this after we have locked the pixels
  1.1174 +    SkColorTable* ctable = bitmap.getColorTable();
  1.1175 +    if (NULL != ctable) {
  1.1176 +        if (ctable->count() == 0) {
  1.1177 +            return false;
  1.1178 +        }
  1.1179 +        // check if we can store in fewer than 8 bits
  1.1180 +        bitDepth = computeBitDepth(ctable->count());
  1.1181 +    }
  1.1182 +
  1.1183 +    return doEncode(stream, bitmap, hasAlpha, colorType,
  1.1184 +                    bitDepth, config, sig_bit);
  1.1185 +}
  1.1186 +
  1.1187 +bool SkPNGImageEncoder::doEncode(SkWStream* stream, const SkBitmap& bitmap,
  1.1188 +                  const bool& hasAlpha, int colorType,
  1.1189 +                  int bitDepth, SkBitmap::Config config,
  1.1190 +                  png_color_8& sig_bit) {
  1.1191 +
  1.1192 +    png_structp png_ptr;
  1.1193 +    png_infop info_ptr;
  1.1194 +
  1.1195 +    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn,
  1.1196 +                                      NULL);
  1.1197 +    if (NULL == png_ptr) {
  1.1198 +        return false;
  1.1199 +    }
  1.1200 +
  1.1201 +    info_ptr = png_create_info_struct(png_ptr);
  1.1202 +    if (NULL == info_ptr) {
  1.1203 +        png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
  1.1204 +        return false;
  1.1205 +    }
  1.1206 +
  1.1207 +    /* Set error handling.  REQUIRED if you aren't supplying your own
  1.1208 +    * error handling functions in the png_create_write_struct() call.
  1.1209 +    */
  1.1210 +    if (setjmp(png_jmpbuf(png_ptr))) {
  1.1211 +        png_destroy_write_struct(&png_ptr, &info_ptr);
  1.1212 +        return false;
  1.1213 +    }
  1.1214 +
  1.1215 +    png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
  1.1216 +
  1.1217 +    /* Set the image information here.  Width and height are up to 2^31,
  1.1218 +    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
  1.1219 +    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
  1.1220 +    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
  1.1221 +    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
  1.1222 +    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
  1.1223 +    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
  1.1224 +    */
  1.1225 +
  1.1226 +    png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
  1.1227 +                 bitDepth, colorType,
  1.1228 +                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
  1.1229 +                 PNG_FILTER_TYPE_BASE);
  1.1230 +
  1.1231 +    // set our colortable/trans arrays if needed
  1.1232 +    png_color paletteColors[256];
  1.1233 +    png_byte trans[256];
  1.1234 +    if (SkBitmap::kIndex8_Config == config) {
  1.1235 +        SkColorTable* ct = bitmap.getColorTable();
  1.1236 +        int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha);
  1.1237 +        png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
  1.1238 +        if (numTrans > 0) {
  1.1239 +            png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL);
  1.1240 +        }
  1.1241 +    }
  1.1242 +
  1.1243 +    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
  1.1244 +    png_write_info(png_ptr, info_ptr);
  1.1245 +
  1.1246 +    const char* srcImage = (const char*)bitmap.getPixels();
  1.1247 +    SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2);
  1.1248 +    char* storage = (char*)rowStorage.get();
  1.1249 +    transform_scanline_proc proc = choose_proc(config, hasAlpha);
  1.1250 +
  1.1251 +    for (int y = 0; y < bitmap.height(); y++) {
  1.1252 +        png_bytep row_ptr = (png_bytep)storage;
  1.1253 +        proc(srcImage, bitmap.width(), storage);
  1.1254 +        png_write_rows(png_ptr, &row_ptr, 1);
  1.1255 +        srcImage += bitmap.rowBytes();
  1.1256 +    }
  1.1257 +
  1.1258 +    png_write_end(png_ptr, info_ptr);
  1.1259 +
  1.1260 +    /* clean up after the write, and free any memory allocated */
  1.1261 +    png_destroy_write_struct(&png_ptr, &info_ptr);
  1.1262 +    return true;
  1.1263 +}
  1.1264 +
  1.1265 +///////////////////////////////////////////////////////////////////////////////
  1.1266 +DEFINE_DECODER_CREATOR(PNGImageDecoder);
  1.1267 +DEFINE_ENCODER_CREATOR(PNGImageEncoder);
  1.1268 +///////////////////////////////////////////////////////////////////////////////
  1.1269 +
  1.1270 +static bool is_png(SkStreamRewindable* stream) {
  1.1271 +    char buf[PNG_BYTES_TO_CHECK];
  1.1272 +    if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
  1.1273 +        !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
  1.1274 +        return true;
  1.1275 +    }
  1.1276 +    return false;
  1.1277 +}
  1.1278 +
  1.1279 +SkImageDecoder* sk_libpng_dfactory(SkStreamRewindable* stream) {
  1.1280 +    if (is_png(stream)) {
  1.1281 +        return SkNEW(SkPNGImageDecoder);
  1.1282 +    }
  1.1283 +    return NULL;
  1.1284 +}
  1.1285 +
  1.1286 +static SkImageDecoder::Format get_format_png(SkStreamRewindable* stream) {
  1.1287 +    if (is_png(stream)) {
  1.1288 +        return SkImageDecoder::kPNG_Format;
  1.1289 +    }
  1.1290 +    return SkImageDecoder::kUnknown_Format;
  1.1291 +}
  1.1292 +
  1.1293 +SkImageEncoder* sk_libpng_efactory(SkImageEncoder::Type t) {
  1.1294 +    return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
  1.1295 +}
  1.1296 +
  1.1297 +static SkImageDecoder_DecodeReg gDReg(sk_libpng_dfactory);
  1.1298 +static SkImageDecoder_FormatReg gFormatReg(get_format_png);
  1.1299 +static SkImageEncoder_EncodeReg gEReg(sk_libpng_efactory);

mercurial