10910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* libs/graphics/images/SkImageDecoder_libpng.cpp
20910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**
30910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Copyright 2006, The Android Open Source Project
40910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**
50910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");
60910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** you may not use this file except in compliance with the License.
70910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** You may obtain a copy of the License at
80910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**
90910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**     http://www.apache.org/licenses/LICENSE-2.0
100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project**
110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** Unless required by applicable law or agreed to in writing, software
120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS,
130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** See the License for the specific language governing permissions and
150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project** limitations under the License.
160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageDecoder.h"
190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkImageEncoder.h"
200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColor.h"
210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h"
220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkDither.h"
230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkMath.h"
240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkScaledBitmapSampler.h"
250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkStream.h"
260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTemplates.h"
270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUtils.h"
280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectextern "C" {
300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "png.h"
310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPNGImageDecoder : public SkImageDecoder {
340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectpublic:
350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    virtual Format getFormat() const {
360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return kPNG_Format;
370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected:
400a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed    virtual bool onDecode(SkStream* stream, SkBitmap* bm, Mode);
410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#ifndef png_jmpbuf
440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#  define png_jmpbuf(png_ptr) ((png_ptr)->jmpbuf)
450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#define PNG_BYTES_TO_CHECK 4
480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/* Automatically clean up after throwing an exception */
500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstruct PNGAutoClean {
510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    PNGAutoClean(png_structp p, png_infop i): png_ptr(p), info_ptr(i) {}
520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    ~PNGAutoClean() {
530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_destroy_read_struct(&png_ptr, &info_ptr, png_infopp_NULL);
540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprivate:
560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_structp png_ptr;
570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_infop info_ptr;
580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_read_fn(png_structp png_ptr, png_bytep data, png_size_t length) {
610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkStream* sk_stream = (SkStream*) png_ptr->io_ptr;
620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    size_t bytes = sk_stream->read(data, length);
630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (bytes != length) {
640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_error(png_ptr, "Read Error!");
650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int sk_read_user_chunk(png_structp png_ptr, png_unknown_chunkp chunk) {
690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkImageDecoder::Peeker* peeker =
700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    (SkImageDecoder::Peeker*)png_get_user_chunk_ptr(png_ptr);
710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // peek() returning true means continue decoding
720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return peeker->peek((const char*)chunk->name, chunk->data, chunk->size) ?
730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            1 : -1;
740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_error_fn(png_structp png_ptr, png_const_charp msg) {
770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0
780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkDebugf("------ png error %s\n", msg);
790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    longjmp(png_jmpbuf(png_ptr), 1);
810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void skip_src_rows(png_structp png_ptr, uint8_t storage[], int count) {
840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < count; i++) {
850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        uint8_t* tmp = storage;
860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool pos_le(int value, int max) {
910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return value > 0 && value <= max;
920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic bool substituteTranspColor(SkBitmap* bm, SkPMColor match) {
950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(bm->config() == SkBitmap::kARGB_8888_Config);
960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool reallyHasAlpha = false;
980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int y = bm->height() - 1; y >= 0; --y) {
1000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPMColor* p = bm->getAddr32(0, y);
1010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int x = bm->width() - 1; x >= 0; --x) {
1020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (match == *p) {
1030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                *p = 0;
1040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                reallyHasAlpha = true;
1050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
1060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            p += 1;
1070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
1080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return reallyHasAlpha;
1100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
1110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1120a81c953145c77abea5ca1df9e84c62d9da96094Mike Reedstatic bool canUpscalePaletteToConfig(SkBitmap::Config dstConfig,
113fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed                                      bool srcHasAlpha) {
1140a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed    switch (dstConfig) {
115fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed        case SkBitmap::kARGB_8888_Config:
116fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed        case SkBitmap::kARGB_4444_Config:
117fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed            return true;
118fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed        case SkBitmap::kRGB_565_Config:
119fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed            // only return true if the src is opaque (since 565 is opaque)
120fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed            return !srcHasAlpha;
121fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed        default:
122fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed            return false;
123fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed    }
124fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed}
125fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed
126fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed// call only if color_type is PALETTE. Returns true if the ctable has alpha
127fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reedstatic bool hasTransparencyInPalette(png_structp png_ptr, png_infop info_ptr) {
128fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed    png_bytep trans;
129fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed    int num_trans;
130fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed
131fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
132fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed        png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
133fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed        return num_trans > 0;
134fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed    }
135fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed    return false;
13618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed}
13718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed
1380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPNGImageDecoder::onDecode(SkStream* sk_stream, SkBitmap* decodedBitmap,
1390a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed                                 Mode mode) {
1400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//    SkAutoTrace    apr("SkPNGImageDecoder::onDecode");
1410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Create and initialize the png_struct with the desired error handler
1430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * functions.  If you want to use the default stderr and longjump method,
1440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * you can supply NULL for the last three parameters.  We also supply the
1450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * the compiler header file version, so that we know if the application
1460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * was compiled with a compatible version of the library.  */
1470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
1480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        NULL, sk_error_fn, NULL);
1490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //   png_voidp user_error_ptr, user_error_fn, user_warning_fn);
1500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (png_ptr == NULL) {
1510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
1520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Allocate/initialize the memory for image information. */
1550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_infop info_ptr = png_create_info_struct(png_ptr);
1560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (info_ptr == NULL) {
1570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_destroy_read_struct(&png_ptr, png_infopp_NULL, png_infopp_NULL);
1580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
1590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    PNGAutoClean autoClean(png_ptr, info_ptr);
1620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Set error handling if you are using the setjmp/longjmp method (this is
1640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * the normal method of doing things with libpng).  REQUIRED unless you
1650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * set up your own error handlers in the png_create_read_struct() earlier.
1660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
1670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (setjmp(png_jmpbuf(png_ptr))) {
1680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
1690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* If you are using replacement read functions, instead of calling
1720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * png_init_io() here you would call:
1730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
1740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_set_read_fn(png_ptr, (void *)sk_stream, sk_read_fn);
1750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* where user_io_ptr is a structure you want available to the callbacks */
1760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* If we have already read some of the signature */
1770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//  png_set_sig_bytes(png_ptr, 0 /* sig_read */ );
1780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // hookup our peeker so we can see any user-chunks the caller may be interested in
1800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_ALWAYS, (png_byte*)"", 0);
1810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (this->getPeeker()) {
1820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_set_read_user_chunk_fn(png_ptr, (png_voidp)this->getPeeker(), sk_read_user_chunk);
1830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* The call to png_read_info() gives us all of the information from the
1860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * PNG file before the first IDAT (image data chunk). */
1870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_read_info(png_ptr, info_ptr);
1880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_uint_32 origWidth, origHeight;
1890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int bit_depth, color_type, interlace_type;
1900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_get_IHDR(png_ptr, info_ptr, &origWidth, &origHeight, &bit_depth, &color_type,
1910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        &interlace_type, int_p_NULL, int_p_NULL);
1920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
1930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* tell libpng to strip 16 bit/color files down to 8 bits/color */
1940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (bit_depth == 16) {
1950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_set_strip_16(png_ptr);
1960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
1970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Extract multiple pixels with bit depths of 1, 2, and 4 from a single
1980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project     * byte into separate bytes (useful for paletted and grayscale images). */
1990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (bit_depth < 8) {
2000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_set_packing(png_ptr);
2010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Expand grayscale images to the full 8 bits from 1, 2, or 4 bits/pixel */
2030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8) {
2040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_set_gray_1_2_4_to_8(png_ptr);
2050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Make a grayscale image into RGB. */
2080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (color_type == PNG_COLOR_TYPE_GRAY ||
2090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
2100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_set_gray_to_rgb(png_ptr);
2110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkBitmap::Config    config;
2140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool                hasAlpha = false;
2150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool                doDither = this->getDitherImage();
2160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkPMColor           theTranspColor = 0; // 0 tells us not to try to match
2170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // check for sBIT chunk data, in case we should disable dithering because
2190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // our data is not truely 8bits per component
2200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (doDither) {
2210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0
2220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkDebugf("----- sBIT %d %d %d %d\n", info_ptr->sig_bit.red,
2230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 info_ptr->sig_bit.green, info_ptr->sig_bit.blue,
2240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 info_ptr->sig_bit.alpha);
2250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
2260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // 0 seems to indicate no information available
2270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (pos_le(info_ptr->sig_bit.red, SK_R16_BITS) &&
2280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                pos_le(info_ptr->sig_bit.green, SK_G16_BITS) &&
2290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                pos_le(info_ptr->sig_bit.blue, SK_B16_BITS)) {
2300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            doDither = false;
2310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
2330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (color_type == PNG_COLOR_TYPE_PALETTE) {
235fda848cde04cfd40ec1be93b30752008f7eb2396Mike Reed        bool paletteHasAlpha = hasTransparencyInPalette(png_ptr, info_ptr);
2360a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed        config = this->getPrefConfig(kIndex_SrcDepth, paletteHasAlpha);
2370a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed        // now see if we can upscale to their requested config
2380a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed        if (!canUpscalePaletteToConfig(config, paletteHasAlpha)) {
2390a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed            config = SkBitmap::kIndex8_Config;
240421adab1be5bb9c1cd419138ceda375aef649077Mike Reed        }
2410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
2420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_color_16p   transpColor = NULL;
2430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int             numTransp = 0;
2440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_get_tRNS(png_ptr, info_ptr, NULL, &numTransp, &transpColor);
2460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        bool valid = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
2480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (valid && numTransp == 1 && transpColor != NULL) {
2500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            /*  Compute our transparent color, which we'll match against later.
2510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                We don't really handle 16bit components properly here, since we
2520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                do our compare *after* the values have been knocked down to 8bit
2530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                which means we will find more matches than we should. The real
2540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                fix seems to be to see the actual 16bit components, do the
2550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                compare, and then knock it down to 8bits ourselves.
2560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            */
2570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (color_type & PNG_COLOR_MASK_COLOR) {
2580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (16 == bit_depth) {
2590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    theTranspColor = SkPackARGB32(0xFF, transpColor->red >> 8,
2600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              transpColor->green >> 8, transpColor->blue >> 8);
2610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                } else {
2620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    theTranspColor = SkPackARGB32(0xFF, transpColor->red,
2630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                      transpColor->green, transpColor->blue);
2640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            } else {    // gray
2660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (16 == bit_depth) {
2670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    theTranspColor = SkPackARGB32(0xFF, transpColor->gray >> 8,
2680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                              transpColor->gray >> 8, transpColor->gray >> 8);
2690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                } else {
2700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    theTranspColor = SkPackARGB32(0xFF, transpColor->gray,
2710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                          transpColor->gray, transpColor->gray);
2720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
2730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
2760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (valid ||
2770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                PNG_COLOR_TYPE_RGB_ALPHA == color_type ||
2780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                PNG_COLOR_TYPE_GRAY_ALPHA == color_type) {
2790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            hasAlpha = true;
2800a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed        }
2810a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed        config = this->getPrefConfig(k32Bit_SrcDepth, hasAlpha);
2820a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed        // now match the request against our capabilities
2830a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed        if (hasAlpha) {
2840a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed            if (config != SkBitmap::kARGB_4444_Config) {
2850a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed                config = SkBitmap::kARGB_8888_Config;
2860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2870a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed        } else {
2880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (config != SkBitmap::kRGB_565_Config &&
2890a81c953145c77abea5ca1df9e84c62d9da96094Mike Reed                config != SkBitmap::kARGB_4444_Config) {
2900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                config = SkBitmap::kARGB_8888_Config;
2910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
2920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
2930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
29418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed
29518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    // sanity check for size
29618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    {
29718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        Sk64 size;
29818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        size.setMul(origWidth, origHeight);
29918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        if (size.isNeg() || !size.is32()) {
30018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            return false;
30118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        }
30218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        // now check that if we are 4-bytes per pixel, we also don't overflow
30318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        if (size.get32() > (0x7FFFFFFF >> 2)) {
30418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            return false;
30518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        }
30618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    }
30718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed
3080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!this->chooseFromOneChoice(config, origWidth, origHeight)) {
3090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
3100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const int sampleSize = this->getSampleSize();
3130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkScaledBitmapSampler sampler(origWidth, origHeight, sampleSize);
3140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    decodedBitmap->setConfig(config, sampler.scaledWidth(),
3160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                             sampler.scaledHeight(), 0);
3170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (SkImageDecoder::kDecodeBounds_Mode == mode) {
3180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return true;
3190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // from here down we are concerned with colortables and pixels
3220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // we track if we actually see a non-opaque pixels, since sometimes a PNG sets its colortype
3240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // to |= PNG_COLOR_MASK_ALPHA, but all of its pixels are in fact opaque. We care, since we
3250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // draw lots faster if we can flag the bitmap has being opaque
3260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    bool reallyHasAlpha = false;
3270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkColorTable* colorTable = NULL;
3280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (color_type == PNG_COLOR_TYPE_PALETTE) {
3300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int num_palette;
3310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_colorp palette;
3320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_bytep trans;
3330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int num_trans;
3340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
3360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        /*  BUGGY IMAGE WORKAROUND
3380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            We hit some images (e.g. fruit_.png) who contain bytes that are == colortable_count
3400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            which is a problem since we use the byte as an index. To work around this we grow
3410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            the colortable by 1 (if its < 256) and duplicate the last color into that slot.
3420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        */
3430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int colorCount = num_palette + (num_palette < 256);
3440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        colorTable = SkNEW_ARGS(SkColorTable, (colorCount));
3460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPMColor* colorPtr = colorTable->lockColors();
3480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
3490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            png_get_tRNS(png_ptr, info_ptr, &trans, &num_trans, NULL);
3500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            hasAlpha = (num_trans > 0);
3510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
3520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            num_trans = 0;
3530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colorTable->setFlags(colorTable->getFlags() | SkColorTable::kColorsAreOpaque_Flag);
3540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // check for bad images that might make us crash
3560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (num_trans > num_palette) {
3570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            num_trans = num_palette;
3580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int index = 0;
3610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int transLessThanFF = 0;
3620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (; index < num_trans; index++) {
3640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            transLessThanFF |= (int)*trans - 0xFF;
3650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *colorPtr++ = SkPreMultiplyARGB(*trans++, palette->red, palette->green, palette->blue);
3660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            palette++;
3670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        reallyHasAlpha |= (transLessThanFF < 0);
3690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (; index < num_palette; index++) {
3710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *colorPtr++ = SkPackARGB32(0xFF, palette->red, palette->green, palette->blue);
3720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            palette++;
3730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // see BUGGY IMAGE WORKAROUND comment above
3760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (num_palette < 256) {
3770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            *colorPtr = colorPtr[-1];
3780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
3790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        colorTable->unlockColors(true);
3800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoUnref aur(colorTable);
3830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
38418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    if (!this->allocPixelRef(decodedBitmap,
385421adab1be5bb9c1cd419138ceda375aef649077Mike Reed                             SkBitmap::kIndex8_Config == config ?
386421adab1be5bb9c1cd419138ceda375aef649077Mike Reed                                colorTable : NULL)) {
3870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
3880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
3890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoLockPixels alp(*decodedBitmap);
3910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */
3930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//  if (color_type == PNG_COLOR_TYPE_RGB_ALPHA)
3940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project//      ; // png_set_swap_alpha(png_ptr);
3950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* swap bytes of 16 bit files to least significant byte first */
3970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    //   png_set_swap(png_ptr);
3980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
3990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Add filler (or alpha) byte (before/after each RGB triplet) */
4000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_GRAY) {
4010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_set_filler(png_ptr, 0xff, PNG_FILLER_AFTER);
4020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Turn on interlace handling.  REQUIRED if you are not using
4050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * png_read_image().  To see how to handle interlacing passes,
4060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * see the png_read_row() method below:
4070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
4080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const int number_passes = interlace_type != PNG_INTERLACE_NONE ?
4090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                        png_set_interlace_handling(png_ptr) : 1;
4100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Optional call to gamma correct and add the background to the palette
4120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * and update info structure.  REQUIRED if you are expecting libpng to
4130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * update the palette for you (ie you selected such a transform above).
4140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
4150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_read_update_info(png_ptr, info_ptr);
4160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (SkBitmap::kIndex8_Config == config && 1 == sampleSize) {
4180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (int i = 0; i < number_passes; i++) {
4190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            for (png_uint_32 y = 0; y < origHeight; y++) {
4200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                uint8_t* bmRow = decodedBitmap->getAddr8(0, y);
4210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
4220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
4230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
4250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkScaledBitmapSampler::SrcConfig sc;
4260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        int srcBytesPerPixel = 4;
4270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
42818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        if (colorTable != NULL) {
4290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sc = SkScaledBitmapSampler::kIndex;
4300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            srcBytesPerPixel = 1;
4310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else if (hasAlpha) {
4320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sc = SkScaledBitmapSampler::kRGBA;
4330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        } else {
4340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sc = SkScaledBitmapSampler::kRGBX;
4350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
43718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        /*  We have to pass the colortable explicitly, since we may have one
43818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            even if our decodedBitmap doesn't, due to the request that we
43918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            upscale png's palette to a direct model
44018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed         */
44118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        SkAutoLockColors ctLock(colorTable);
44218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        if (!sampler.begin(decodedBitmap, sc, doDither, ctLock.colors())) {
44318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            return false;
44418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        }
4450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const int height = decodedBitmap->height();
4460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
44718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        if (number_passes > 1) {
44818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            SkAutoMalloc storage(origWidth * origHeight * srcBytesPerPixel);
44918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            uint8_t* base = (uint8_t*)storage.get();
45018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            size_t rb = origWidth * srcBytesPerPixel;
45118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed
45218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            for (int i = 0; i < number_passes; i++) {
45318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed                uint8_t* row = base;
45418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed                for (png_uint_32 y = 0; y < origHeight; y++) {
45518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed                    uint8_t* bmRow = row;
45618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed                    png_read_rows(png_ptr, &bmRow, png_bytepp_NULL, 1);
45718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed                    row += rb;
45818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed                }
4590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
46018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            // now sample it
46118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            base += sampler.srcY0() * rb;
46218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            for (int y = 0; y < height; y++) {
46318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed                reallyHasAlpha |= sampler.next(base);
46418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed                base += sampler.srcDY() * rb;
46518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            }
46618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        } else {
46718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            SkAutoMalloc storage(origWidth * srcBytesPerPixel);
4680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            uint8_t* srcRow = (uint8_t*)storage.get();
4690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            skip_src_rows(png_ptr, srcRow, sampler.srcY0());
4700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            for (int y = 0; y < height; y++) {
4720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                uint8_t* tmp = srcRow;
4730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                png_read_rows(png_ptr, &tmp, png_bytepp_NULL, 1);
4740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                reallyHasAlpha |= sampler.next(srcRow);
4750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                if (y < height - 1) {
4760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                    skip_src_rows(png_ptr, srcRow, sampler.srcDY() - 1);
4770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                }
4780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
47918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed
4800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // skip the rest of the rows (if any)
4810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            png_uint_32 read = (height - 1) * sampler.srcDY() +
4820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                               sampler.srcY0() + 1;
4830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkASSERT(read <= origHeight);
4840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            skip_src_rows(png_ptr, srcRow, origHeight - read);
4850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
4860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* read rest of file, and get additional chunks in info_ptr - REQUIRED */
4890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_read_end(png_ptr, info_ptr);
4900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (0 != theTranspColor) {
4920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        reallyHasAlpha |= substituteTranspColor(decodedBitmap, theTranspColor);
4930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
4940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    decodedBitmap->setIsOpaque(!reallyHasAlpha);
4950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
4960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
4970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
4980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
4990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkColorPriv.h"
5010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkUnPreMultiply.h"
5020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void sk_write_fn(png_structp png_ptr, png_bytep data, png_size_t len) {
5040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkWStream* sk_stream = (SkWStream*)png_ptr->io_ptr;
5050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!sk_stream->write(data, len)) {
5060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_error(png_ptr, "sk_write_fn Error!");
5070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projecttypedef void (*transform_scanline_proc)(const char* SK_RESTRICT src,
5110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                        int width, char* SK_RESTRICT dst);
5120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_565(const char* SK_RESTRICT src, int width,
5140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                   char* SK_RESTRICT dst) {
5150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const uint16_t* SK_RESTRICT srcP = (const uint16_t*)src;
5160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < width; i++) {
5170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned c = *srcP++;
5180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkPacked16ToR32(c);
5190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkPacked16ToG32(c);
5200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkPacked16ToB32(c);
5210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_888(const char* SK_RESTRICT src, int width,
5250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                   char* SK_RESTRICT dst) {
5260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
5270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < width; i++) {
5280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPMColor c = *srcP++;
5290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkGetPackedR32(c);
5300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkGetPackedG32(c);
5310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkGetPackedB32(c);
5320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_444(const char* SK_RESTRICT src, int width,
5360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                   char* SK_RESTRICT dst) {
5370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
5380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < width; i++) {
5390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPMColor16 c = *srcP++;
5400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkPacked4444ToR32(c);
5410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkPacked4444ToG32(c);
5420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = SkPacked4444ToB32(c);
5430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_8888(const char* SK_RESTRICT src, int width,
5470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                    char* SK_RESTRICT dst) {
5480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPMColor* SK_RESTRICT srcP = (const SkPMColor*)src;
5490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkUnPreMultiply::Scale* SK_RESTRICT table =
5500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                              SkUnPreMultiply::GetScaleTable();
5510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < width; i++) {
5530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPMColor c = *srcP++;
5540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned a = SkGetPackedA32(c);
5550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned r = SkGetPackedR32(c);
5560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned g = SkGetPackedG32(c);
5570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned b = SkGetPackedB32(c);
5580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (0 != a && 255 != a) {
5600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkUnPreMultiply::Scale scale = table[a];
5610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            r = SkUnPreMultiply::ApplyScale(scale, r);
5620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            g = SkUnPreMultiply::ApplyScale(scale, g);
5630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            b = SkUnPreMultiply::ApplyScale(scale, b);
5640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
5650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = r;
5660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = g;
5670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = b;
5680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = a;
5690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_4444(const char* SK_RESTRICT src, int width,
5730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                    char* SK_RESTRICT dst) {
5740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPMColor16* SK_RESTRICT srcP = (const SkPMColor16*)src;
5750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkUnPreMultiply::Scale* SK_RESTRICT table =
5760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                              SkUnPreMultiply::GetScaleTable();
5770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = 0; i < width; i++) {
5790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPMColor16 c = *srcP++;
5800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned a = SkPacked4444ToA32(c);
5810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned r = SkPacked4444ToR32(c);
5820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned g = SkPacked4444ToG32(c);
5830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        unsigned b = SkPacked4444ToB32(c);
5840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (0 != a && 255 != a) {
5860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            SkUnPreMultiply::Scale scale = table[a];
5870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            r = SkUnPreMultiply::ApplyScale(scale, r);
5880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            g = SkUnPreMultiply::ApplyScale(scale, g);
5890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            b = SkUnPreMultiply::ApplyScale(scale, b);
5900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
5910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = r;
5920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = g;
5930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = b;
5940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        *dst++ = a;
5950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
5960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
5970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
5980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic void transform_scanline_index8(const char* SK_RESTRICT src, int width,
5990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                      char* SK_RESTRICT dst) {
6000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    memcpy(dst, src, width);
6010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic transform_scanline_proc choose_proc(SkBitmap::Config config,
6040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                           bool hasAlpha) {
6050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // we don't care about search on alpha if we're kIndex8, since only the
6060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // colortable packing cares about that distinction, not the pixels
6070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (SkBitmap::kIndex8_Config == config) {
6080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        hasAlpha = false;   // we store false in the table entries for kIndex8
6090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    static const struct {
6120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkBitmap::Config        fConfig;
6130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        bool                    fHasAlpha;
6140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        transform_scanline_proc fProc;
6150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } gMap[] = {
6160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        { SkBitmap::kRGB_565_Config,    false,  transform_scanline_565 },
6170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        { SkBitmap::kARGB_8888_Config,  false,  transform_scanline_888 },
6180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        { SkBitmap::kARGB_8888_Config,  true,   transform_scanline_8888 },
6190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        { SkBitmap::kARGB_4444_Config,  false,  transform_scanline_444 },
6200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        { SkBitmap::kARGB_4444_Config,  true,   transform_scanline_4444 },
6210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        { SkBitmap::kIndex8_Config,     false,   transform_scanline_index8 },
6220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    };
6230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int i = SK_ARRAY_COUNT(gMap) - 1; i >= 0; --i) {
6250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (gMap[i].fConfig == config && gMap[i].fHasAlpha == hasAlpha) {
6260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return gMap[i].fProc;
6270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    sk_throw();
6300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return NULL;
6310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// return the minimum legal bitdepth (by png standards) for this many colortable
6340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// entries. SkBitmap always stores in 8bits per pixel, but for colorcount <= 16,
6350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project// we can use fewer bits per in png
6360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic int computeBitDepth(int colorCount) {
6370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#if 0
6380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int bits = SkNextLog2(colorCount);
6390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkASSERT(bits >= 1 && bits <= 8);
6400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // now we need bits itself to be a power of 2 (e.g. 1, 2, 4, 8)
6410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return SkNextPow2(bits);
6420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#else
6430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // for the moment, we don't know how to pack bitdepth < 8
6440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return 8;
6450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#endif
6460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
6470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project/*  Pack palette[] with the corresponding colors, and if hasAlpha is true, also
6490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    pack trans[] and return the number of trans[] entries written. If hasAlpha
6500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    is false, the return value will always be 0.
6510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    Note: this routine takes care of unpremultiplying the RGB values when we
6530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    have alpha in the colortable, since png doesn't support premul colors
6540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project*/
6550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic inline int pack_palette(SkColorTable* ctable,
6560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                               png_color* SK_RESTRICT palette,
6570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                               png_byte* SK_RESTRICT trans, bool hasAlpha) {
6580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoLockColors alc(ctable);
6590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const SkPMColor* SK_RESTRICT colors = alc.colors();
6600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const int ctCount = ctable->count();
6610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int i, num_trans = 0;
6620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (hasAlpha) {
6640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        /*  first see if we have some number of fully opaque at the end of the
6650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            ctable. PNG allows num_trans < num_palette, but all of the trans
6660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            entries must come first in the palette. If I was smarter, I'd
6670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            reorder the indices and ctable so that all non-opaque colors came
6680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            first in the palette. But, since that would slow down the encode,
6690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            I'm leaving the indices and ctable order as is, and just looking
6700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            at the tail of the ctable for opaqueness.
6710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        */
6720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        num_trans = ctCount;
6730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (i = ctCount - 1; i >= 0; --i) {
6740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            if (SkGetPackedA32(colors[i]) != 0xFF) {
6750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                break;
6760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            }
6770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            num_trans -= 1;
6780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        const SkUnPreMultiply::Scale* SK_RESTRICT table =
6810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                            SkUnPreMultiply::GetScaleTable();
6820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        for (i = 0; i < num_trans; i++) {
6840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const SkPMColor c = *colors++;
6850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const unsigned a = SkGetPackedA32(c);
6860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            const SkUnPreMultiply::Scale s = table[a];
6870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            trans[i] = a;
6880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            palette[i].red = SkUnPreMultiply::ApplyScale(s, SkGetPackedR32(c));
6890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            palette[i].green = SkUnPreMultiply::ApplyScale(s,SkGetPackedG32(c));
6900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            palette[i].blue = SkUnPreMultiply::ApplyScale(s, SkGetPackedB32(c));
6910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
6920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // now fall out of this if-block to use common code for the trailing
6930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // opaque entries
6940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
6950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
6960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // these (remaining) entries are opaque
6970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (i = num_trans; i < ctCount; i++) {
6980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        SkPMColor c = *colors++;
6990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        palette[i].red = SkGetPackedR32(c);
7000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        palette[i].green = SkGetPackedG32(c);
7010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        palette[i].blue = SkGetPackedB32(c);
7020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return num_trans;
7040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
7050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectclass SkPNGImageEncoder : public SkImageEncoder {
7070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectprotected:
7080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    virtual bool onEncode(SkWStream* stream, const SkBitmap& bm, int quality);
7090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project};
7100910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7110910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectbool SkPNGImageEncoder::onEncode(SkWStream* stream, const SkBitmap& bitmap,
7120910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                 int /*quality*/) {
7130910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkBitmap::Config config = bitmap.getConfig();
7140910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7150910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const bool hasAlpha = !bitmap.isOpaque();
7160910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int colorType = PNG_COLOR_MASK_COLOR;
7170910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    int bitDepth = 8;   // default for color
7180910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_color_8 sig_bit;
7190910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7200910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    switch (config) {
7210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case SkBitmap::kIndex8_Config:
7220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colorType |= PNG_COLOR_MASK_PALETTE;
7230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            // fall through to the ARGB_8888 case
7240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case SkBitmap::kARGB_8888_Config:
7250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.red = 8;
7260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.green = 8;
7270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.blue = 8;
7280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.alpha = 8;
7290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
7300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case SkBitmap::kARGB_4444_Config:
7310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.red = 4;
7320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.green = 4;
7330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.blue = 4;
7340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.alpha = 4;
7350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
7360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        case SkBitmap::kRGB_565_Config:
7370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.red = 5;
7380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.green = 6;
7390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.blue = 5;
7400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            sig_bit.alpha = 0;
7410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            break;
7420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        default:
7430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return false;
7440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (hasAlpha) {
7470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // don't specify alpha if we're a palette, even if our ctable has alpha
7480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (!(colorType & PNG_COLOR_MASK_PALETTE)) {
7490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            colorType |= PNG_COLOR_MASK_ALPHA;
7500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
7510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    } else {
7520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        sig_bit.alpha = 0;
7530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoLockPixels alp(bitmap);
7560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // readyToDraw checks for pixels (and colortable if that is required)
7570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (!bitmap.readyToDraw()) {
7580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
7590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    // we must do this after we have locked the pixels
7620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkColorTable* ctable = bitmap.getColorTable();
7630910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL != ctable) {
7640910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        if (ctable->count() == 0) {
7650910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project            return false;
7660910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        }
7670910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        // check if we can store in fewer than 8 bits
7680910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        bitDepth = computeBitDepth(ctable->count());
7690910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7700910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7710910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_structp png_ptr;
7720910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_infop info_ptr;
7730910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7740910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, sk_error_fn,
7750910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                                      NULL);
7760910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == png_ptr) {
7770910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
7780910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7790910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7800910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    info_ptr = png_create_info_struct(png_ptr);
7810910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (NULL == info_ptr) {
7820910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_destroy_write_struct(&png_ptr,  png_infopp_NULL);
7830910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
7840910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7850910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7860910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Set error handling.  REQUIRED if you aren't supplying your own
7870910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * error handling functions in the png_create_write_struct() call.
7880910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
7890910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (setjmp(png_jmpbuf(png_ptr))) {
7900910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_destroy_write_struct(&png_ptr, &info_ptr);
7910910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return false;
7920910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
7930910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7940910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_set_write_fn(png_ptr, (void*)stream, sk_write_fn, png_flush_ptr_NULL);
7950910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
7960910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* Set the image information here.  Width and height are up to 2^31,
7970910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * bit_depth is one of 1, 2, 4, 8, or 16, but valid values also depend on
7980910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * the color_type selected. color_type is one of PNG_COLOR_TYPE_GRAY,
7990910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * PNG_COLOR_TYPE_GRAY_ALPHA, PNG_COLOR_TYPE_PALETTE, PNG_COLOR_TYPE_RGB,
8000910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * or PNG_COLOR_TYPE_RGB_ALPHA.  interlace is either PNG_INTERLACE_NONE or
8010910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * PNG_INTERLACE_ADAM7, and the compression_type and filter_type MUST
8020910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    * currently be PNG_COMPRESSION_TYPE_BASE and PNG_FILTER_TYPE_BASE. REQUIRED
8030910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    */
8040910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8050910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_set_IHDR(png_ptr, info_ptr, bitmap.width(), bitmap.height(),
8060910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 bitDepth, colorType,
8070910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE,
8080910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project                 PNG_FILTER_TYPE_BASE);
8090910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
81018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    // set our colortable/trans arrays if needed
81118987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    png_color paletteColors[256];
81218987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    png_byte trans[256];
81318987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    if (SkBitmap::kIndex8_Config == config) {
81418987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        SkColorTable* ct = bitmap.getColorTable();
81518987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        int numTrans = pack_palette(ct, paletteColors, trans, hasAlpha);
81618987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        png_set_PLTE(png_ptr, info_ptr, paletteColors, ct->count());
81718987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        if (numTrans > 0) {
81818987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed            png_set_tRNS(png_ptr, info_ptr, trans, numTrans, NULL);
81918987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed        }
82018987486da6931c8698a13e3fbac3b22f0c965a6Mike Reed    }
8210910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8220910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_set_sBIT(png_ptr, info_ptr, &sig_bit);
8230910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_write_info(png_ptr, info_ptr);
8240910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8250910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    const char* srcImage = (const char*)bitmap.getPixels();
8260910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    SkAutoSMalloc<1024> rowStorage(bitmap.width() << 2);
8270910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    char* storage = (char*)rowStorage.get();
8280910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    transform_scanline_proc proc = choose_proc(config, hasAlpha);
8290910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8300910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    for (int y = 0; y < bitmap.height(); y++) {
8310910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_bytep row_ptr = (png_bytep)storage;
8320910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        proc(srcImage, bitmap.width(), storage);
8330910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        png_write_rows(png_ptr, &row_ptr, 1);
8340910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        srcImage += bitmap.rowBytes();
8350910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8360910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8370910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_write_end(png_ptr, info_ptr);
8380910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8390910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    /* clean up after the write, and free any memory allocated */
8400910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    png_destroy_write_struct(&png_ptr, &info_ptr);
8410910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return true;
8420910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
8430910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8440910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project///////////////////////////////////////////////////////////////////////////////
8450910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8460910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project#include "SkTRegistry.h"
8470910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8480910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkImageDecoder* DFactory(SkStream* stream) {
8490910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    char buf[PNG_BYTES_TO_CHECK];
8500910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    if (stream->read(buf, PNG_BYTES_TO_CHECK) == PNG_BYTES_TO_CHECK &&
8510910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        !png_sig_cmp((png_bytep) buf, (png_size_t)0, PNG_BYTES_TO_CHECK)) {
8520910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project        return SkNEW(SkPNGImageDecoder);
8530910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    }
8540910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return NULL;
8550910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
8560910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8570910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkImageEncoder* EFactory(SkImageEncoder::Type t) {
8580910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project    return (SkImageEncoder::kPNG_Type == t) ? SkNEW(SkPNGImageEncoder) : NULL;
8590910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project}
8600910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Project
8610910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkTRegistry<SkImageEncoder*, SkImageEncoder::Type> gEReg(EFactory);
8620910916c0f7b951ee55c4b7c6358295b9bca0565The Android Open Source Projectstatic SkTRegistry<SkImageDecoder*, SkStream*> gDReg(DFactory);
863