Bug 863123 - Set APNG attributes on the right frame, rather than one frame behind. r=seth
authorJoe Drew <joe@drew.ca>
Mon, 22 Apr 2013 10:57:17 -0400
changeset 129481 7950bce752ccf3694cfd1cea1ab21d0381fa1ae6
parent 129480 7ff57f0a926550c638c9cc6b9434712a549cabf5
child 129482 6c9af867443cab152d6b1997f769e652e6567fd1
push idunknown
push userunknown
push dateunknown
reviewersseth
bugs863123
milestone23.0a1
Bug 863123 - Set APNG attributes on the right frame, rather than one frame behind. r=seth
image/decoders/nsPNGDecoder.cpp
image/decoders/nsPNGDecoder.h
--- a/image/decoders/nsPNGDecoder.cpp
+++ b/image/decoders/nsPNGDecoder.cpp
@@ -49,71 +49,64 @@ GetPNGDecoderAccountingLog()
 /* limit image dimensions (bug #251381) */
 #define MOZ_PNG_MAX_DIMENSION 1000000L
 
 // For size decodes
 #define WIDTH_OFFSET 16
 #define HEIGHT_OFFSET (WIDTH_OFFSET + 4)
 #define BYTES_NEEDED_FOR_DIMENSIONS (HEIGHT_OFFSET + 4)
 
-struct AnimFrameInfo
-{
-  AnimFrameInfo()
-   : mDispose(RasterImage::kDisposeKeep)
-   , mBlend(RasterImage::kBlendOver)
-   , mTimeout(0)
-  {}
+nsPNGDecoder::AnimFrameInfo::AnimFrameInfo()
+ : mDispose(RasterImage::kDisposeKeep)
+ , mBlend(RasterImage::kBlendOver)
+ , mTimeout(0)
+{}
 
 #ifdef PNG_APNG_SUPPORTED
-  AnimFrameInfo(png_structp aPNG, png_infop aInfo)
-   : mDispose(RasterImage::kDisposeKeep)
-   , mBlend(RasterImage::kBlendOver)
-   , mTimeout(0)
-  {
-    png_uint_16 delay_num, delay_den;
-    /* delay, in seconds is delay_num/delay_den */
-    png_byte dispose_op;
-    png_byte blend_op;
-    delay_num = png_get_next_frame_delay_num(aPNG, aInfo);
-    delay_den = png_get_next_frame_delay_den(aPNG, aInfo);
-    dispose_op = png_get_next_frame_dispose_op(aPNG, aInfo);
-    blend_op = png_get_next_frame_blend_op(aPNG, aInfo);
+nsPNGDecoder::AnimFrameInfo::AnimFrameInfo(png_structp aPNG, png_infop aInfo)
+ : mDispose(RasterImage::kDisposeKeep)
+ , mBlend(RasterImage::kBlendOver)
+ , mTimeout(0)
+{
+  png_uint_16 delay_num, delay_den;
+  /* delay, in seconds is delay_num/delay_den */
+  png_byte dispose_op;
+  png_byte blend_op;
+  delay_num = png_get_next_frame_delay_num(aPNG, aInfo);
+  delay_den = png_get_next_frame_delay_den(aPNG, aInfo);
+  dispose_op = png_get_next_frame_dispose_op(aPNG, aInfo);
+  blend_op = png_get_next_frame_blend_op(aPNG, aInfo);
 
-    if (delay_num == 0) {
-      mTimeout = 0; // SetFrameTimeout() will set to a minimum
-    } else {
-      if (delay_den == 0)
-        delay_den = 100; // so says the APNG spec
+  if (delay_num == 0) {
+    mTimeout = 0; // SetFrameTimeout() will set to a minimum
+  } else {
+    if (delay_den == 0)
+      delay_den = 100; // so says the APNG spec
 
-      // Need to cast delay_num to float to have a proper division and
-      // the result to int to avoid compiler warning
-      mTimeout = static_cast<int32_t>(static_cast<double>(delay_num) * 1000 / delay_den);
-    }
-
-    if (dispose_op == PNG_DISPOSE_OP_PREVIOUS) {
-      mDispose = RasterImage::kDisposeRestorePrevious;
-    } else if (dispose_op == PNG_DISPOSE_OP_BACKGROUND) {
-      mDispose = RasterImage::kDisposeClear;
-    } else {
-      mDispose = RasterImage::kDisposeKeep;
-    }
+    // Need to cast delay_num to float to have a proper division and
+    // the result to int to avoid compiler warning
+    mTimeout = static_cast<int32_t>(static_cast<double>(delay_num) * 1000 / delay_den);
+  }
 
-    if (blend_op == PNG_BLEND_OP_SOURCE) {
-      mBlend = RasterImage::kBlendSource;
-    } else {
-      mBlend = RasterImage::kBlendOver;
-    }
+  if (dispose_op == PNG_DISPOSE_OP_PREVIOUS) {
+    mDispose = RasterImage::kDisposeRestorePrevious;
+  } else if (dispose_op == PNG_DISPOSE_OP_BACKGROUND) {
+    mDispose = RasterImage::kDisposeClear;
+  } else {
+    mDispose = RasterImage::kDisposeKeep;
   }
+
+  if (blend_op == PNG_BLEND_OP_SOURCE) {
+    mBlend = RasterImage::kBlendSource;
+  } else {
+    mBlend = RasterImage::kBlendOver;
+  }
+}
 #endif
 
-  RasterImage::FrameDisposalMethod mDispose;
-  RasterImage::FrameBlendMethod mBlend;
-  int32_t mTimeout;
-};
-
 // First 8 bytes of a PNG file
 const uint8_t 
 nsPNGDecoder::pngSignatureBytes[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
 
 nsPNGDecoder::nsPNGDecoder(RasterImage &aImage)
  : Decoder(aImage),
    mPNG(nullptr), mInfo(nullptr),
    mCMSLine(nullptr), interlacebuf(nullptr),
@@ -158,48 +151,48 @@ void nsPNGDecoder::CreateFrame(png_uint_
 
   PR_LOG(GetPNGDecoderAccountingLog(), PR_LOG_DEBUG,
          ("PNGDecoderAccounting: nsPNGDecoder::CreateFrame -- created "
           "image frame with %dx%d pixels in container %p",
           width, height,
           &mImage));
 
   mFrameHasNoAlpha = true;
+
+#ifdef PNG_APNG_SUPPORTED
+  if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
+    mAnimInfo = AnimFrameInfo(mPNG, mInfo);
+  }
+#endif
 }
 
 // set timeout and frame disposal method for the current frame
 void nsPNGDecoder::EndImageFrame()
 {
   if (mFrameIsHidden)
     return;
 
   mNumFrames++;
 
   RasterImage::FrameAlpha alpha;
   if (mFrameHasNoAlpha)
     alpha = RasterImage::kFrameOpaque;
   else
     alpha = RasterImage::kFrameHasAlpha;
 
-  AnimFrameInfo animInfo;
-
 #ifdef PNG_APNG_SUPPORTED
   uint32_t numFrames = GetFrameCount();
 
   // We can't use mPNG->num_frames_read as it may be one ahead.
   if (numFrames > 1) {
     PostInvalidation(mFrameRect);
   }
-
-  if (png_get_valid(mPNG, mInfo, PNG_INFO_acTL)) {
-    animInfo = AnimFrameInfo(mPNG, mInfo);
-  }
 #endif
 
-  PostFrameStop(alpha, animInfo.mDispose, animInfo.mTimeout, animInfo.mBlend);
+  PostFrameStop(alpha, mAnimInfo.mDispose, mAnimInfo.mTimeout, mAnimInfo.mBlend);
 }
 
 void
 nsPNGDecoder::InitInternal()
 {
   mCMSMode = gfxPlatform::GetCMSMode();
   if ((mDecodeFlags & DECODER_NO_COLORSPACE_CONVERSION) != 0)
     mCMSMode = eCMSMode_Off;
--- a/image/decoders/nsPNGDecoder.h
+++ b/image/decoders/nsPNGDecoder.h
@@ -85,16 +85,30 @@ public:
   uint8_t mChannels;
   bool mFrameHasNoAlpha;
   bool mFrameIsHidden;
 
   // whether CMS or premultiplied alpha are forced off
   uint32_t mCMSMode;
   bool mDisablePremultipliedAlpha;
 
+  struct AnimFrameInfo
+  {
+    AnimFrameInfo();
+#ifdef PNG_APNG_SUPPORTED
+    AnimFrameInfo(png_structp aPNG, png_infop aInfo);
+#endif
+
+    RasterImage::FrameDisposalMethod mDispose;
+    RasterImage::FrameBlendMethod mBlend;
+    int32_t mTimeout;
+  };
+
+  AnimFrameInfo mAnimInfo;
+
   // The number of frames we've finished.
   uint32_t mNumFrames;
   
   /*
    * libpng callbacks
    *
    * We put these in the class so that they can access protected members.
    */