Chromium Code Reviews| 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..1dce5cd15c0518e3676a9a1ea126100940a8ecbe 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), |
| + scale_fallback(false), |
| done(false) { |
| } |
| @@ -117,6 +120,7 @@ class PngDecoderState { |
| output(NULL), |
| width(0), |
| height(0), |
| + scale_fallback(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 scale_fallback; |
| + |
| // Set to true when we've found the end of the data. |
| bool done; |
| @@ -330,6 +338,17 @@ 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)); |
| + DCHECK(memcmp(chunk->name, kPngScaleChunk, 5) == 0); // guaranteed by libpng |
|
sail
2012/10/09 22:01:37
sentence fragment
benrg
2012/10/10 02:18:13
Done.
|
| + if (chunk->size == 0) { |
| + state->scale_fallback = 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 +425,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 +440,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 +470,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* scale_fallback) { |
| 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 (scale_fallback) |
| + *scale_fallback = state.scale_fallback; |
| 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(); |