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..1c5e068d040475d80b1ebb528d976bec3f383281 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), |
| + percent(-1), |
| done(false) { |
| } |
| @@ -117,6 +120,7 @@ class PngDecoderState { |
| output(NULL), |
| width(0), |
| height(0), |
| + percent(-1), |
| done(false) { |
| } |
| @@ -138,6 +142,9 @@ class PngDecoderState { |
| int width; |
| int height; |
| + // Image percentage scale (normally 100) from the csCl chunk. |
| + int percent; |
| + |
| // Set to true when we've found the end of the data. |
| bool done; |
| @@ -330,6 +337,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)); |
| + DCHECK(memcmp(chunk->name, kPngScaleChunk, 5) == 0); // guaranteed by libpng |
| + if (chunk->size == 2) { |
| + state->percent = chunk->data[0] * 0x100 + chunk->data[1]; |
| + return 1; // processed |
| + } else { |
| + 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,62 +440,53 @@ 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); |
|
benrg
2012/10/05 18:21:41
This call wasn't in the 4-argument version of PNGC
|
| - 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); |
| + bool ok = DecodeInternal(input, input_size, &state); |
| + if (ok) { |
|
oshima
2012/10/05 20:33:11
I think
if (Decode...) {
return true;
}
...
ret
|
| + *w = state.width; |
| + *h = state.height; |
| + } else { |
| output->clear(); |
|
benrg
2012/10/05 18:21:41
Before the refactoring the output was cleared only
|
| - return false; |
| } |
| - |
| - *w = state.width; |
| - *h = state.height; |
| - return true; |
| + return ok; |
| } |
| // static |
| bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| - SkBitmap* bitmap) { |
| + SkBitmap* bitmap, int* percent) { |
| 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) { |
| - return false; |
| + bool ok = DecodeInternal(input, input_size, &state); |
|
oshima
2012/10/05 20:33:11
ditto.
|
| + if (ok) { |
| + bitmap->setIsOpaque(state.is_opaque); |
| + if (percent) |
| + *percent = state.percent; |
| } |
| + return ok; |
| +} |
| - // Set the bitmap's opaqueness based on what we saw. |
| - bitmap->setIsOpaque(state.is_opaque); |
| - |
| - return true; |
| +// static |
| +bool PNGCodec::Decode(const unsigned char* input, size_t input_size, |
| + SkBitmap* bitmap) { |
| + return Decode(input, input_size, bitmap, NULL); |
| } |
| // static |