Index: gfx/codec/png_codec.cc |
diff --git a/gfx/codec/png_codec.cc b/gfx/codec/png_codec.cc |
index eaf94f05e622fab04ccc99b3c41e6100a9b4f779..9db0095daaad6390ca66a6b5c7065a909ca704d8 100644 |
--- a/gfx/codec/png_codec.cc |
+++ b/gfx/codec/png_codec.cc |
@@ -541,21 +541,53 @@ void ConvertBGRAtoRGB(const unsigned char* bgra, int pixel_width, |
} |
} |
-// Automatically destroys the given write structs on destruction to make |
-// cleanup and error handling code cleaner. |
-class PngWriteStructDestroyer { |
- public: |
- PngWriteStructDestroyer(png_struct** ps, png_info** pi) : ps_(ps), pi_(pi) { |
- } |
- ~PngWriteStructDestroyer() { |
- png_destroy_write_struct(ps_, pi_); |
+// The type of functions usable for converting between pixel formats. |
+typedef void (*FormatConverter)(const unsigned char* in, int w, |
+ unsigned char* out, bool* is_opaque); |
+ |
+// libpng uses a wacky setjmp-based API, which makes the compiler nervous. |
+// We constrain all of the calls we make to libpng where the setjmp() is in |
+// place to this function. |
+// Returns true on success. |
+bool DoLibpngWrite(png_struct* png_ptr, png_info* info_ptr, |
+ PngEncoderState* state, |
+ int width, int height, int row_byte_width, |
+ const unsigned char* input, |
+ int png_output_color_type, int output_color_components, |
+ FormatConverter converter) { |
+ // Make sure to not declare any locals here -- locals in the presence |
+ // of setjmp() in C++ code makes gcc complain. |
+ |
+ if (setjmp(png_jmpbuf(png_ptr))) |
+ return false; |
+ |
+ // Set our callback for libpng to give us the data. |
+ png_set_write_fn(png_ptr, state, EncoderWriteCallback, NULL); |
+ |
+ png_set_IHDR(png_ptr, info_ptr, width, height, 8, png_output_color_type, |
+ PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, |
+ PNG_FILTER_TYPE_DEFAULT); |
+ png_write_info(png_ptr, info_ptr); |
+ |
+ if (!converter) { |
+ // No conversion needed, give the data directly to libpng. |
+ for (int y = 0; y < height; y ++) { |
+ png_write_row(png_ptr, |
+ const_cast<unsigned char*>(&input[y * row_byte_width])); |
+ } |
+ } else { |
+ // Needs conversion using a separate buffer. |
+ unsigned char* row = new unsigned char[width * output_color_components]; |
+ for (int y = 0; y < height; y ++) { |
+ converter(&input[y * row_byte_width], width, row, NULL); |
+ png_write_row(png_ptr, row); |
+ } |
+ delete[] row; |
} |
- private: |
- png_struct** ps_; |
- png_info** pi_; |
- DISALLOW_EVIL_CONSTRUCTORS(PngWriteStructDestroyer); |
-}; |
+ png_write_end(png_ptr, info_ptr); |
+ return true; |
+} |
} // namespace |
@@ -566,8 +598,7 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format, |
std::vector<unsigned char>* output) { |
// Run to convert an input row into the output row format, NULL means no |
// conversion is necessary. |
- void (*converter)(const unsigned char* in, int w, unsigned char* out, |
- bool* is_opaque) = NULL; |
+ FormatConverter converter = NULL; |
int input_color_components, output_color_components; |
int png_output_color_type; |
@@ -635,42 +666,15 @@ bool PNGCodec::Encode(const unsigned char* input, ColorFormat format, |
png_destroy_write_struct(&png_ptr, NULL); |
return false; |
} |
- PngWriteStructDestroyer 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; |
- } |
- // Set our callback for libpng to give us the data. |
PngEncoderState state(output); |
- png_set_write_fn(png_ptr, &state, EncoderWriteCallback, NULL); |
+ bool success = DoLibpngWrite(png_ptr, info_ptr, &state, |
+ w, h, row_byte_width, input, |
+ png_output_color_type, output_color_components, |
+ converter); |
+ png_destroy_write_struct(&png_ptr, &info_ptr); |
- png_set_IHDR(png_ptr, info_ptr, w, h, 8, png_output_color_type, |
- PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, |
- PNG_FILTER_TYPE_DEFAULT); |
- png_write_info(png_ptr, info_ptr); |
- |
- if (!converter) { |
- // No conversion needed, give the data directly to libpng. |
- for (int y = 0; y < h; y ++) { |
- png_write_row(png_ptr, |
- const_cast<unsigned char*>(&input[y * row_byte_width])); |
- } |
- } else { |
- // Needs conversion using a separate buffer. |
- unsigned char* row = new unsigned char[w * output_color_components]; |
- for (int y = 0; y < h; y ++) { |
- converter(&input[y * row_byte_width], w, row, NULL); |
- png_write_row(png_ptr, row); |
- } |
- delete[] row; |
- } |
- |
- png_write_end(png_ptr, info_ptr); |
- return true; |
+ return success; |
} |
// static |