| Index: ui/gfx/codec/png_codec.cc
|
| diff --git a/ui/gfx/codec/png_codec.cc b/ui/gfx/codec/png_codec.cc
|
| index 474fbc9f3999b9464a990aaef0f255080c0e2a6e..82ffcd2b28e2840820ac65d78deee8527c0a6cfe 100644
|
| --- a/ui/gfx/codec/png_codec.cc
|
| +++ b/ui/gfx/codec/png_codec.cc
|
| @@ -94,6 +94,8 @@ const double kMaxGamma = 21474.83; // Maximum gamma accepted by png library.
|
| const double kDefaultGamma = 2.2;
|
| const double kInverseGamma = 1.0 / kDefaultGamma;
|
|
|
| +const png_byte kPngScaleChunk[5] = { 'c', 's', 'C', 'l', 0 };
|
| +
|
| class PngDecoderState {
|
| public:
|
| // Output is a vector<unsigned char>.
|
| @@ -105,6 +107,7 @@ class PngDecoderState {
|
| output(o),
|
| width(0),
|
| height(0),
|
| + fell_back_to_1x(false),
|
| done(false) {
|
| }
|
|
|
| @@ -117,6 +120,7 @@ class PngDecoderState {
|
| output(NULL),
|
| width(0),
|
| height(0),
|
| + fell_back_to_1x(false),
|
| done(false) {
|
| }
|
|
|
| @@ -138,6 +142,10 @@ class PngDecoderState {
|
| int width;
|
| int height;
|
|
|
| + // True if a csCl chunk is present, indicating that GRIT didn't find an image
|
| + // at the proper scale and fell back to 100%.
|
| + bool fell_back_to_1x;
|
| +
|
| // Set to true when we've found the end of the data.
|
| bool done;
|
|
|
| @@ -330,6 +338,18 @@ void DecodeEndCallback(png_struct* png_ptr, png_info* info) {
|
| state->done = true;
|
| }
|
|
|
| +int DecodeUserChunkCallback(png_struct* png_ptr, png_unknown_chunk* chunk) {
|
| + PngDecoderState* state = static_cast<PngDecoderState*>(
|
| + png_get_user_chunk_ptr(png_ptr));
|
| + // We instructed libpng to call us only for csCl chunks.
|
| + DCHECK(memcmp(chunk->name, kPngScaleChunk, 5) == 0);
|
| + if (chunk->size == 0) {
|
| + state->fell_back_to_1x = true;
|
| + return 1; // processed
|
| + }
|
| + return 0; // unrecognized
|
| +}
|
| +
|
| // Automatically destroys the given read structs on destruction to make
|
| // cleanup and error handling code cleaner.
|
| class PngReadStructDestroyer {
|
| @@ -406,12 +426,8 @@ void LogLibPNGEncodeWarning(png_structp png_ptr, png_const_charp warning_msg) {
|
| DLOG(ERROR) << "libpng encode warning: " << warning_msg;
|
| }
|
|
|
| -} // namespace
|
| -
|
| -// static
|
| -bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
|
| - ColorFormat format, std::vector<unsigned char>* output,
|
| - int* w, int* h) {
|
| +bool DecodeInternal(const unsigned char* input, size_t input_size,
|
| + PngDecoderState* state) {
|
| png_struct* png_ptr = NULL;
|
| png_info* info_ptr = NULL;
|
| if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr))
|
| @@ -425,23 +441,29 @@ bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
|
| return false;
|
| }
|
|
|
| - PngDecoderState state(format, output);
|
| -
|
| png_set_error_fn(png_ptr, NULL, LogLibPNGDecodeError, LogLibPNGDecodeWarning);
|
| - png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback,
|
| - &DecodeRowCallback, &DecodeEndCallback);
|
| - png_process_data(png_ptr,
|
| - info_ptr,
|
| - const_cast<unsigned char*>(input),
|
| - input_size);
|
| -
|
| - if (!state.done) {
|
| - // Fed it all the data but the library didn't think we got all the data, so
|
| - // this file must be truncated.
|
| + png_set_progressive_read_fn(png_ptr, state, DecodeInfoCallback,
|
| + DecodeRowCallback, DecodeEndCallback);
|
| + png_set_keep_unknown_chunks(png_ptr, 3, const_cast<png_byte*>(kPngScaleChunk),
|
| + 1); // keep only csCl
|
| + png_set_read_user_chunk_fn(png_ptr, state, DecodeUserChunkCallback);
|
| + png_process_data(png_ptr, info_ptr,
|
| + const_cast<unsigned char*>(input), input_size);
|
| + return state->done;
|
| +}
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +// static
|
| +bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
|
| + ColorFormat format, std::vector<unsigned char>* output,
|
| + int* w, int* h) {
|
| + PngDecoderState state(format, output);
|
| + if (!DecodeInternal(input, input_size, &state)) {
|
| output->clear();
|
| return false;
|
| }
|
| -
|
| *w = state.width;
|
| *h = state.height;
|
| return true;
|
| @@ -449,41 +471,24 @@ bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
|
|
|
| // static
|
| bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
|
| - SkBitmap* bitmap) {
|
| + SkBitmap* bitmap, bool* fell_back_to_1x) {
|
| DCHECK(bitmap);
|
| - png_struct* png_ptr = NULL;
|
| - png_info* info_ptr = NULL;
|
| - if (!BuildPNGStruct(input, input_size, &png_ptr, &info_ptr))
|
| - return false;
|
| -
|
| - PngReadStructDestroyer destroyer(&png_ptr, &info_ptr);
|
| - if (setjmp(png_jmpbuf(png_ptr))) {
|
| - // The destroyer will ensure that the structures are cleaned up in this
|
| - // case, even though we may get here as a jump from random parts of the
|
| - // PNG library called below.
|
| - return false;
|
| - }
|
| -
|
| PngDecoderState state(bitmap);
|
| -
|
| - png_set_progressive_read_fn(png_ptr, &state, &DecodeInfoCallback,
|
| - &DecodeRowCallback, &DecodeEndCallback);
|
| - png_process_data(png_ptr,
|
| - info_ptr,
|
| - const_cast<unsigned char*>(input),
|
| - input_size);
|
| -
|
| - if (!state.done) {
|
| + if (!DecodeInternal(input, input_size, &state))
|
| return false;
|
| - }
|
| -
|
| - // Set the bitmap's opaqueness based on what we saw.
|
| bitmap->setIsOpaque(state.is_opaque);
|
| -
|
| + if (fell_back_to_1x)
|
| + *fell_back_to_1x = state.fell_back_to_1x;
|
| return true;
|
| }
|
|
|
| // static
|
| +bool PNGCodec::Decode(const unsigned char* input, size_t input_size,
|
| + SkBitmap* bitmap) {
|
| + return Decode(input, input_size, bitmap, NULL);
|
| +}
|
| +
|
| +// static
|
| SkBitmap* PNGCodec::CreateSkBitmapFromBGRAFormat(
|
| std::vector<unsigned char>& bgra, int width, int height) {
|
| SkBitmap* bitmap = new SkBitmap();
|
|
|