Bug 1191090 - Use the normal PNG decoder for PNG metadata decodes. r=tn

--HG--
extra : rebase_source : c0d1f9f8e376cbe4ebf1921d3e1edf85234e8f7b
This commit is contained in:
Seth Fowler 2015-08-10 15:34:27 -07:00
parent 3069169b59
commit c0f83249c8

View File

@ -47,11 +47,6 @@ GetPNGDecoderAccountingLog()
# define MOZ_PNG_MAX_DIMENSION 32767
#endif
// For metadata decodes.
#define WIDTH_OFFSET 16
#define HEIGHT_OFFSET (WIDTH_OFFSET + 4)
#define BYTES_NEEDED_FOR_DIMENSIONS (HEIGHT_OFFSET + 4)
nsPNGDecoder::AnimFrameInfo::AnimFrameInfo()
: mDispose(DisposalMethod::KEEP)
, mBlend(BlendMethod::OVER)
@ -148,6 +143,7 @@ nsPNGDecoder::CreateFrame(png_uint_32 aXOffset, png_uint_32 aYOffset,
gfx::SurfaceFormat aFormat)
{
MOZ_ASSERT(HasSize());
MOZ_ASSERT(!IsMetadataDecode());
if (aFormat == gfx::SurfaceFormat::B8G8R8A8) {
PostHasTransparency();
@ -226,11 +222,6 @@ nsPNGDecoder::EndImageFrame()
void
nsPNGDecoder::InitInternal()
{
// For metadata decodes, we don't need to initialize the PNG decoder.
if (IsMetadataDecode()) {
return;
}
mCMSMode = gfxPlatform::GetCMSMode();
if (GetDecodeFlags() & imgIContainer::FLAG_DECODE_NO_COLORSPACE_CONVERSION) {
mCMSMode = eCMSMode_Off;
@ -257,8 +248,6 @@ nsPNGDecoder::InitInternal()
122, 84, 88, 116, '\0'}; // zTXt
#endif
// For full decodes, do png init stuff
// Initialize the container's source image header
// Always decode to 24 bit pixdepth
@ -321,73 +310,24 @@ nsPNGDecoder::WriteInternal(const char* aBuffer, uint32_t aCount)
{
MOZ_ASSERT(!HasError(), "Shouldn't call WriteInternal after error!");
// If we only want width/height, we don't need to go through libpng.
if (IsMetadataDecode()) {
// libpng uses setjmp/longjmp for error handling. Set it up.
if (setjmp(png_jmpbuf(mPNG))) {
// Are we done?
if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS) {
return;
// We exited early. If mSuccessfulEarlyFinish isn't true, then we
// encountered an error. We might not really know what caused it, but it
// makes more sense to blame the data.
if (!mSuccessfulEarlyFinish && !HasError()) {
PostDataError();
}
// Scan the header for the width and height bytes
uint32_t pos = 0;
const uint8_t* bptr = (uint8_t*)aBuffer;
while (pos < aCount && mHeaderBytesRead < BYTES_NEEDED_FOR_DIMENSIONS) {
// Verify the signature bytes
if (mHeaderBytesRead < sizeof(pngSignatureBytes)) {
if (bptr[pos] != nsPNGDecoder::pngSignatureBytes[mHeaderBytesRead]) {
PostDataError();
return;
}
}
// Get width and height bytes into the buffer
if ((mHeaderBytesRead >= WIDTH_OFFSET) &&
(mHeaderBytesRead < BYTES_NEEDED_FOR_DIMENSIONS)) {
mSizeBytes[mHeaderBytesRead - WIDTH_OFFSET] = bptr[pos];
}
pos ++;
mHeaderBytesRead ++;
}
// If we're done now, verify the data and set up the container
if (mHeaderBytesRead == BYTES_NEEDED_FOR_DIMENSIONS) {
// Grab the width and height, accounting for endianness (thanks libpng!)
uint32_t width = png_get_uint_32(mSizeBytes);
uint32_t height = png_get_uint_32(mSizeBytes + 4);
// Too big?
if ((width > MOZ_PNG_MAX_DIMENSION) || (height > MOZ_PNG_MAX_DIMENSION)) {
PostDataError();
return;
}
// Post our size to the superclass
PostSize(width, height);
}
// Otherwise, we're doing a standard decode
} else {
// libpng uses setjmp/longjmp for error handling - set the buffer
if (setjmp(png_jmpbuf(mPNG))) {
// We might not really know what caused the error, but it makes more
// sense to blame the data.
if (!mSuccessfulEarlyFinish && !HasError()) {
PostDataError();
}
png_destroy_read_struct(&mPNG, &mInfo, nullptr);
return;
}
// Pass the data off to libpng
png_process_data(mPNG, mInfo, (unsigned char*)aBuffer, aCount);
png_destroy_read_struct(&mPNG, &mInfo, nullptr);
return;
}
// Pass the data off to libpng.
png_process_data(mPNG, mInfo,
reinterpret_cast<unsigned char*>(const_cast<char*>((aBuffer))),
aCount);
}
// Sets up gamma pre-correction in libpng before our callback gets called.
@ -546,6 +486,12 @@ nsPNGDecoder::info_callback(png_structp png_ptr, png_infop info_ptr)
png_longjmp(decoder->mPNG, 1);
}
if (decoder->IsMetadataDecode()) {
// We have the size, so we don't need to decode any further.
decoder->mSuccessfulEarlyFinish = true;
png_longjmp(decoder->mPNG, 1);
}
if (color_type == PNG_COLOR_TYPE_PALETTE) {
png_set_expand(png_ptr);
}