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 |