Bug 1057904 (Part 1) - Use RawAccessRef in FrameBlender and related classes and clean up. r=tn
authorSeth Fowler <seth@mozilla.com>
Wed, 01 Oct 2014 17:16:36 -0700
changeset 231507 320de51add949cc1fe5a28d047e0326637da1670
parent 231506 3f9e0be6d08f51e87aa4b0aacf9022bf844f6128
child 231508 60d6c5549706957a9443e8b7aa384627f9e7f1b2
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstn
bugs1057904
milestone35.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1057904 (Part 1) - Use RawAccessRef in FrameBlender and related classes and clean up. r=tn
image/src/FrameBlender.cpp
image/src/FrameBlender.h
image/src/FrameSequence.cpp
image/src/FrameSequence.h
image/src/RasterImage.cpp
image/src/imgFrame.cpp
image/src/imgFrame.h
image/src/moz.build
--- a/image/src/FrameBlender.cpp
+++ b/image/src/FrameBlender.cpp
@@ -1,186 +1,149 @@
 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "FrameBlender.h"
 
 #include "mozilla/MemoryReporting.h"
+#include "mozilla/Move.h"
 #include "MainThreadUtils.h"
 
 #include "pixman.h"
 
 namespace mozilla {
 
 using namespace gfx;
 
 namespace image {
 
-FrameBlender::FrameBlender(FrameSequence* aSequenceToUse /* = nullptr */)
- : mFrames(aSequenceToUse)
- , mAnim(nullptr)
+FrameBlender::FrameBlender()
+ : mAnim(nullptr)
  , mLoopCount(-1)
 {
-  if (!mFrames) {
-    mFrames = new FrameSequence();
-  }
 }
 
 FrameBlender::~FrameBlender()
 {
   delete mAnim;
 }
 
-already_AddRefed<FrameSequence>
-FrameBlender::GetFrameSequence()
+already_AddRefed<imgFrame>
+FrameBlender::GetFrame(uint32_t aFrameNum)
 {
-  nsRefPtr<FrameSequence> seq(mFrames);
-  return seq.forget();
+  if (mAnim && mAnim->lastCompositedFrameIndex == int32_t(aFrameNum)) {
+    nsRefPtr<imgFrame> frame = mAnim->compositingFrame.get();
+    return frame.forget();
+  }
+  return RawGetFrame(aFrameNum);
 }
 
 already_AddRefed<imgFrame>
-FrameBlender::GetFrame(uint32_t framenum) const
+FrameBlender::RawGetFrame(uint32_t aFrameNum)
 {
   if (!mAnim) {
-    NS_ASSERTION(framenum == 0, "Don't ask for a frame > 0 if we're not animated!");
-    return mFrames->GetFrame(0).GetFrame();
-  }
-  if (mAnim->lastCompositedFrameIndex == int32_t(framenum)) {
-    return mAnim->compositingFrame.GetFrame();
+    NS_ASSERTION(aFrameNum == 0,
+                 "Don't ask for a frame > 0 if we're not animated!");
+    aFrameNum = 0;
   }
-  return mFrames->GetFrame(framenum).GetFrame();
-}
-
-already_AddRefed<imgFrame>
-FrameBlender::RawGetFrame(uint32_t framenum) const
-{
-  if (!mAnim) {
-    NS_ASSERTION(framenum == 0, "Don't ask for a frame > 0 if we're not animated!");
-    return mFrames->GetFrame(0).GetFrame();
+  if (aFrameNum >= mFrames.Length()) {
+    return nullptr;
   }
-  return mFrames->GetFrame(framenum).GetFrame();
+  nsRefPtr<imgFrame> frame = mFrames[aFrameNum].get();
+  return frame.forget();
 }
 
 uint32_t
 FrameBlender::GetNumFrames() const
 {
-  return mFrames->GetNumFrames();
+  return mFrames.Length();
 }
 
 int32_t
-FrameBlender::GetTimeoutForFrame(uint32_t framenum) const
+FrameBlender::GetTimeoutForFrame(uint32_t aFrameNum)
 {
-  nsRefPtr<imgFrame> frame = RawGetFrame(framenum);
+  nsRefPtr<imgFrame> frame = RawGetFrame(aFrameNum);
   const int32_t timeout = frame->GetRawTimeout();
+
   // Ensure a minimal time between updates so we don't throttle the UI thread.
   // consider 0 == unspecified and make it fast but not too fast.  Unless we have
   // a single loop GIF. See bug 890743, bug 125137, bug 139677, and bug 207059.
   // The behavior of recent IE and Opera versions seems to be:
   // IE 6/Win:
   //   10 - 50ms go 100ms
   //   >50ms go correct speed
   // Opera 7 final/Win:
   //   10ms goes 100ms
   //   >10ms go correct speed
   // It seems that there are broken tools out there that set a 0ms or 10ms
   // timeout when they really want a "default" one.  So munge values in that
   // range.
-  if (timeout >= 0 && timeout <= 10 && mLoopCount != 0)
+  if (timeout >= 0 && timeout <= 10 && mLoopCount != 0) {
     return 100;
+  }
+
   return timeout;
 }
 
 void
 FrameBlender::SetLoopCount(int32_t aLoopCount)
 {
   mLoopCount = aLoopCount;
 }
 
 int32_t
 FrameBlender::GetLoopCount() const
 {
   return mLoopCount;
 }
 
 void
-FrameBlender::RemoveFrame(uint32_t framenum)
+FrameBlender::RemoveFrame(uint32_t aFrameNum)
 {
-  NS_ABORT_IF_FALSE(framenum < GetNumFrames(), "Deleting invalid frame!");
-
-  mFrames->RemoveFrame(framenum);
+  MOZ_ASSERT(aFrameNum < GetNumFrames(), "Deleting invalid frame!");
+  mFrames.RemoveElementAt(aFrameNum);
 }
 
 void
 FrameBlender::ClearFrames()
 {
-  // Forget our old frame sequence, letting whoever else has it deal with it.
-  mFrames = new FrameSequence();
+  mFrames.Clear();
+  mFrames.Compact();
 }
 
 void
-FrameBlender::InsertFrame(uint32_t framenum, imgFrame* aFrame)
-{
-  NS_ABORT_IF_FALSE(framenum <= GetNumFrames(), "Inserting invalid frame!");
-  mFrames->InsertFrame(framenum, aFrame);
-  if (GetNumFrames() > 1) {
-    EnsureAnimExists();
-  }
-}
-
-already_AddRefed<imgFrame>
-FrameBlender::SwapFrame(uint32_t framenum, imgFrame* aFrame)
+FrameBlender::InsertFrame(uint32_t aFrameNum, RawAccessFrameRef&& aRef)
 {
-  NS_ABORT_IF_FALSE(framenum < GetNumFrames(), "Swapping invalid frame!");
-
-  nsRefPtr<imgFrame> ret;
+  MOZ_ASSERT(aRef, "Need a reference to a frame");
+  MOZ_ASSERT(aFrameNum <= GetNumFrames(), "Inserting invalid frame");
 
-  // Steal the imgFrame from wherever it's currently stored
-  if (mAnim && mAnim->lastCompositedFrameIndex == int32_t(framenum)) {
-    ret = mAnim->compositingFrame.Forget();
-    mAnim->lastCompositedFrameIndex = -1;
-    nsRefPtr<imgFrame> toDelete(mFrames->SwapFrame(framenum, aFrame));
-  } else {
-    ret = mFrames->SwapFrame(framenum, aFrame);
+  mFrames.InsertElementAt(aFrameNum, Move(aRef));
+  if (GetNumFrames() == 2) {
+    MOZ_ASSERT(!mAnim, "Shouldn't have an animation context yet");
+    mAnim = new Anim();
   }
 
-  return ret.forget();
-}
-
-void
-FrameBlender::EnsureAnimExists()
-{
-  if (!mAnim) {
-    // Create the animation context
-    mAnim = new Anim();
-
-    // We should only get into this code path directly after we've created our
-    // second frame (hence we know we're animated).
-    MOZ_ASSERT(GetNumFrames() == 2);
-  }
+  MOZ_ASSERT(GetNumFrames() < 2 || mAnim,
+             "If we're animated we should have an animation context now");
 }
 
 //******************************************************************************
 // DoBlend gets called when the timer for animation get fired and we have to
 // update the composited frame of the animation.
 bool
 FrameBlender::DoBlend(nsIntRect* aDirtyRect,
                       uint32_t aPrevFrameIndex,
                       uint32_t aNextFrameIndex)
 {
-  if (!aDirtyRect) {
-    return false;
-  }
+  nsRefPtr<imgFrame> prevFrame = GetFrame(aPrevFrameIndex);
+  nsRefPtr<imgFrame> nextFrame = GetFrame(aNextFrameIndex);
 
-  const FrameDataPair& prevFrame = mFrames->GetFrame(aPrevFrameIndex);
-  const FrameDataPair& nextFrame = mFrames->GetFrame(aNextFrameIndex);
-  if (!prevFrame.HasFrameData() || !nextFrame.HasFrameData()) {
-    return false;
-  }
+  MOZ_ASSERT(prevFrame && nextFrame, "Should have frames here");
 
   int32_t prevFrameDisposalMethod = prevFrame->GetFrameDisposalMethod();
   if (prevFrameDisposalMethod == FrameBlender::kDisposeRestorePrevious &&
       !mAnim->compositingPrevFrame)
     prevFrameDisposalMethod = FrameBlender::kDisposeClear;
 
   nsIntRect prevFrameRect = prevFrame->GetRect();
   bool isFullPrevFrame = (prevFrameRect.x == 0 && prevFrameRect.y == 0 &&
@@ -255,24 +218,23 @@ FrameBlender::DoBlend(nsIntRect* aDirtyR
   if (mAnim->lastCompositedFrameIndex == int32_t(aNextFrameIndex)) {
     return true;
   }
 
   bool needToBlankComposite = false;
 
   // Create the Compositing Frame
   if (!mAnim->compositingFrame) {
-    mAnim->compositingFrame.SetFrame(new imgFrame());
-    nsresult rv =
-      mAnim->compositingFrame->InitForDecoder(mSize, SurfaceFormat::B8G8R8A8);
+    nsRefPtr<imgFrame> newFrame = new imgFrame;
+    nsresult rv = newFrame->InitForDecoder(mSize, SurfaceFormat::B8G8R8A8);
     if (NS_FAILED(rv)) {
-      mAnim->compositingFrame.SetFrame(nullptr);
+      mAnim->compositingFrame.reset();
       return false;
     }
-    mAnim->compositingFrame.LockAndGetData();
+    mAnim->compositingFrame = newFrame->RawAccessRef();
     needToBlankComposite = true;
   } else if (int32_t(aNextFrameIndex) != mAnim->lastCompositedFrameIndex+1) {
 
     // If we are not drawing on top of last composited frame,
     // then we are building a new composite frame, so let's clear it first.
     needToBlankComposite = true;
   }
 
@@ -305,119 +267,117 @@ FrameBlender::DoBlend(nsIntRect* aDirtyR
 
   if (doDisposal) {
     // Dispose of previous: clear, restore, or keep (copy)
     switch (prevFrameDisposalMethod) {
       case FrameBlender::kDisposeClear:
         if (needToBlankComposite) {
           // If we just created the composite, it could have anything in its
           // buffer. Clear whole frame
-          ClearFrame(mAnim->compositingFrame.GetFrameData(),
+          ClearFrame(mAnim->compositingFrame->GetRawData(),
                      mAnim->compositingFrame->GetRect());
         } else {
           // Only blank out previous frame area (both color & Mask/Alpha)
-          ClearFrame(mAnim->compositingFrame.GetFrameData(),
+          ClearFrame(mAnim->compositingFrame->GetRawData(),
                      mAnim->compositingFrame->GetRect(),
                      prevFrameRect);
         }
         break;
 
       case FrameBlender::kDisposeClearAll:
-        ClearFrame(mAnim->compositingFrame.GetFrameData(),
+        ClearFrame(mAnim->compositingFrame->GetRawData(),
                    mAnim->compositingFrame->GetRect());
         break;
 
       case FrameBlender::kDisposeRestorePrevious:
         // It would be better to copy only the area changed back to
         // compositingFrame.
         if (mAnim->compositingPrevFrame) {
-          CopyFrameImage(mAnim->compositingPrevFrame.GetFrameData(),
+          CopyFrameImage(mAnim->compositingPrevFrame->GetRawData(),
                          mAnim->compositingPrevFrame->GetRect(),
-                         mAnim->compositingFrame.GetFrameData(),
+                         mAnim->compositingFrame->GetRawData(),
                          mAnim->compositingFrame->GetRect());
 
           // destroy only if we don't need it for this frame's disposal
           if (nextFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious)
-            mAnim->compositingPrevFrame.SetFrame(nullptr);
+            mAnim->compositingPrevFrame.reset();
         } else {
-          ClearFrame(mAnim->compositingFrame.GetFrameData(),
+          ClearFrame(mAnim->compositingFrame->GetRawData(),
                      mAnim->compositingFrame->GetRect());
         }
         break;
 
       default:
         // Copy previous frame into compositingFrame before we put the new frame on top
         // Assumes that the previous frame represents a full frame (it could be
         // smaller in size than the container, as long as the frame before it erased
         // itself)
         // Note: Frame 1 never gets into DoBlend(), so (aNextFrameIndex - 1) will
         // always be a valid frame number.
         if (mAnim->lastCompositedFrameIndex != int32_t(aNextFrameIndex - 1)) {
           if (isFullPrevFrame && !prevFrame->GetIsPaletted()) {
             // Just copy the bits
-            CopyFrameImage(prevFrame.GetFrameData(),
+            CopyFrameImage(prevFrame->GetRawData(),
                            prevFrame->GetRect(),
-                           mAnim->compositingFrame.GetFrameData(),
+                           mAnim->compositingFrame->GetRawData(),
                            mAnim->compositingFrame->GetRect());
           } else {
             if (needToBlankComposite) {
               // Only blank composite when prev is transparent or not full.
               if (prevFrame->GetHasAlpha() || !isFullPrevFrame) {
-                ClearFrame(mAnim->compositingFrame.GetFrameData(),
+                ClearFrame(mAnim->compositingFrame->GetRawData(),
                            mAnim->compositingFrame->GetRect());
               }
             }
-            DrawFrameTo(prevFrame.GetFrameData(), prevFrameRect,
+            DrawFrameTo(prevFrame->GetRawData(), prevFrameRect,
                         prevFrame->PaletteDataLength(),
                         prevFrame->GetHasAlpha(),
-                        mAnim->compositingFrame.GetFrameData(),
+                        mAnim->compositingFrame->GetRawData(),
                         mAnim->compositingFrame->GetRect(),
                         FrameBlendMethod(prevFrame->GetBlendMethod()));
           }
         }
     }
   } else if (needToBlankComposite) {
     // If we just created the composite, it could have anything in it's
     // buffers. Clear them
-    ClearFrame(mAnim->compositingFrame.GetFrameData(),
+    ClearFrame(mAnim->compositingFrame->GetRawData(),
                mAnim->compositingFrame->GetRect());
   }
 
   // Check if the frame we are composing wants the previous image restored afer
   // it is done. Don't store it (again) if last frame wanted its image restored
   // too
   if ((nextFrameDisposalMethod == FrameBlender::kDisposeRestorePrevious) &&
       (prevFrameDisposalMethod != FrameBlender::kDisposeRestorePrevious)) {
     // We are storing the whole image.
     // It would be better if we just stored the area that nextFrame is going to
     // overwrite.
     if (!mAnim->compositingPrevFrame) {
-      mAnim->compositingPrevFrame.SetFrame(new imgFrame());
-      nsresult rv =
-        mAnim->compositingPrevFrame->InitForDecoder(mSize,
-                                                    SurfaceFormat::B8G8R8A8);
+      nsRefPtr<imgFrame> newFrame = new imgFrame;
+      nsresult rv = newFrame->InitForDecoder(mSize, SurfaceFormat::B8G8R8A8);
       if (NS_FAILED(rv)) {
-        mAnim->compositingPrevFrame.SetFrame(nullptr);
+        mAnim->compositingPrevFrame.reset();
         return false;
       }
 
-      mAnim->compositingPrevFrame.LockAndGetData();
+      mAnim->compositingPrevFrame = newFrame->RawAccessRef();
     }
 
-    CopyFrameImage(mAnim->compositingFrame.GetFrameData(),
+    CopyFrameImage(mAnim->compositingFrame->GetRawData(),
                    mAnim->compositingFrame->GetRect(),
-                   mAnim->compositingPrevFrame.GetFrameData(),
+                   mAnim->compositingPrevFrame->GetRawData(),
                    mAnim->compositingPrevFrame->GetRect());
   }
 
   // blit next frame into it's correct spot
-  DrawFrameTo(nextFrame.GetFrameData(), nextFrameRect,
+  DrawFrameTo(nextFrame->GetRawData(), nextFrameRect,
               nextFrame->PaletteDataLength(),
               nextFrame->GetHasAlpha(),
-              mAnim->compositingFrame.GetFrameData(),
+              mAnim->compositingFrame->GetRawData(),
               mAnim->compositingFrame->GetRect(),
               FrameBlendMethod(nextFrame->GetBlendMethod()));
 
   // Set timeout of CompositeFrame to timeout of frame we just composed
   // Bug 177948
   int32_t timeout = nextFrame->GetRawTimeout();
   mAnim->compositingFrame->SetRawTimeout(timeout);
 
@@ -585,24 +545,33 @@ FrameBlender::Discard()
   // Delete all the decoded frames, then clear the array.
   ClearFrames();
 }
 
 size_t
 FrameBlender::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
                                                       MallocSizeOf aMallocSizeOf) const
 {
-  size_t n = mFrames->SizeOfDecodedWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
+  size_t n = 0;
+
+  for (uint32_t i = 0; i < mFrames.Length(); ++i) {
+    n += mFrames[i]->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
+                                                                   aMallocSizeOf);
+  }
 
   if (mAnim) {
     if (mAnim->compositingFrame) {
-      n += mAnim->compositingFrame->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
+      n += mAnim->compositingFrame
+                ->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
+                                                                aMallocSizeOf);
     }
     if (mAnim->compositingPrevFrame) {
-      n += mAnim->compositingPrevFrame->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
+      n += mAnim->compositingPrevFrame
+                ->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation,
+                                                                aMallocSizeOf);
     }
   }
 
   return n;
 }
 
 void
 FrameBlender::ResetAnimation()
--- a/image/src/FrameBlender.h
+++ b/image/src/FrameBlender.h
@@ -4,72 +4,67 @@
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_imagelib_FrameBlender_h_
 #define mozilla_imagelib_FrameBlender_h_
 
 #include "mozilla/MemoryReporting.h"
 #include "gfxTypes.h"
-#include "FrameSequence.h"
+#include "imgFrame.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace image {
 
-class imgFrame;
-
 /**
  * FrameBlender stores and gives access to imgFrames. It also knows how to
  * blend frames from previous to next, looping if necessary.
  *
  * All logic about when and whether to blend are external to FrameBlender.
  */
 class FrameBlender
 {
 public:
 
   /**
    * Create a new FrameBlender with a given frame sequence.
    *
    * If aSequenceToUse is not specified, it will be allocated automatically.
    */
-  explicit FrameBlender(FrameSequence* aSequenceToUse = nullptr);
+  explicit FrameBlender();
   ~FrameBlender();
 
   bool DoBlend(nsIntRect* aDirtyRect, uint32_t aPrevFrameIndex,
                uint32_t aNextFrameIndex);
 
-  already_AddRefed<FrameSequence> GetFrameSequence();
-
   /**
    * Get the @aIndex-th frame, including (if applicable) any results of
    * blending.
    */
-  already_AddRefed<imgFrame> GetFrame(uint32_t aIndex) const;
+  already_AddRefed<imgFrame> GetFrame(uint32_t aIndex);
 
   /**
    * Get the @aIndex-th frame in the frame index, ignoring results of blending.
    */
-  already_AddRefed<imgFrame> RawGetFrame(uint32_t aIndex) const;
+  already_AddRefed<imgFrame> RawGetFrame(uint32_t aIndex);
 
-  void InsertFrame(uint32_t framenum, imgFrame* aFrame);
-  void RemoveFrame(uint32_t framenum);
-  already_AddRefed<imgFrame> SwapFrame(uint32_t framenum, imgFrame* aFrame);
+  void InsertFrame(uint32_t aFrameNum, RawAccessFrameRef&& aRef);
+  void RemoveFrame(uint32_t aFrameNum);
   void ClearFrames();
 
   /* The total number of frames in this image. */
   uint32_t GetNumFrames() const;
 
   /*
    * Returns the frame's adjusted timeout. If the animation loops and the timeout
    * falls in between a certain range then the timeout is adjusted so that
    * it's never 0. If the animation does not loop then no adjustments are made.
    */
-  int32_t GetTimeoutForFrame(uint32_t framenum) const;
+  int32_t GetTimeoutForFrame(uint32_t aFrameNum);
 
   /*
    * Set number of times to loop the image.
    * @note -1 means loop forever.
    */
   void SetLoopCount(int32_t aLoopCount);
   int32_t GetLoopCount() const;
 
@@ -120,33 +115,31 @@ private:
     /** For managing blending of frames
      *
      * Some animations will use the compositingFrame to composite images
      * and just hand this back to the caller when it is time to draw the frame.
      * NOTE: When clearing compositingFrame, remember to set
      *       lastCompositedFrameIndex to -1.  Code assume that if
      *       lastCompositedFrameIndex >= 0 then compositingFrame exists.
      */
-    FrameDataPair compositingFrame;
+    RawAccessFrameRef compositingFrame;
 
     /** the previous composited frame, for DISPOSE_RESTORE_PREVIOUS
      *
      * The Previous Frame (all frames composited up to the current) needs to be
      * stored in cases where the image specifies it wants the last frame back
      * when it's done with the current frame.
      */
-    FrameDataPair compositingPrevFrame;
+    RawAccessFrameRef compositingPrevFrame;
 
     Anim() :
       lastCompositedFrameIndex(-1)
     {}
   };
 
-  void EnsureAnimExists();
-
   /** Clears an area of <aFrame> with transparent black.
    *
    * @param aFrameData Target Frame data
    * @param aFrameRect The rectangle of the data pointed ot by aFrameData
    *
    * @note Does also clears the transparancy mask
    */
   static void ClearFrame(uint8_t* aFrameData, const nsIntRect& aFrameRect);
@@ -175,17 +168,17 @@ private:
    */
   static nsresult DrawFrameTo(const uint8_t *aSrcData, const nsIntRect& aSrcRect,
                               uint32_t aSrcPaletteLength, bool aSrcHasAlpha,
                               uint8_t *aDstPixels, const nsIntRect& aDstRect,
                               FrameBlendMethod aBlendMethod);
 
 private: // data
   //! All the frames of the image
-  nsRefPtr<FrameSequence> mFrames;
+  nsTArray<RawAccessFrameRef> mFrames;
   nsIntSize mSize;
   Anim* mAnim;
   int32_t mLoopCount;
 };
 
 } // namespace image
 } // namespace mozilla
 
deleted file mode 100644
--- a/image/src/FrameSequence.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "FrameSequence.h"
-
-namespace mozilla {
-namespace image {
-
-FrameSequence::~FrameSequence()
-{
-  ClearFrames();
-}
-
-const FrameDataPair&
-FrameSequence::GetFrame(uint32_t framenum) const
-{
-  if (framenum >= mFrames.Length()) {
-    static FrameDataPair empty;
-    return empty;
-  }
-
-  return mFrames[framenum];
-}
-
-uint32_t
-FrameSequence::GetNumFrames() const
-{
-  return mFrames.Length();
-}
-
-void
-FrameSequence::RemoveFrame(uint32_t framenum)
-{
-  NS_ABORT_IF_FALSE(framenum < mFrames.Length(), "Deleting invalid frame!");
-
-  mFrames.RemoveElementAt(framenum);
-}
-
-void
-FrameSequence::ClearFrames()
-{
-  // Since FrameDataPair holds an nsAutoPtr to its frame, clearing the mFrames
-  // array also deletes all the frames.
-  mFrames.Clear();
-}
-
-void
-FrameSequence::InsertFrame(uint32_t framenum, imgFrame* aFrame)
-{
-  NS_ABORT_IF_FALSE(framenum <= mFrames.Length(), "Inserting invalid frame!");
-  mFrames.InsertElementAt(framenum, aFrame);
-  if (GetNumFrames() > 1) {
-    // If we're creating our second element, we now know we're animated.
-    // Therefore, we need to lock the first frame too.
-    if (GetNumFrames() == 2) {
-      mFrames[0].LockAndGetData();
-    }
-
-    // Whenever we have more than one frame, we always lock *all* our frames
-    // so we have all the image data pointers.
-    mFrames[framenum].LockAndGetData();
-  }
-}
-
-already_AddRefed<imgFrame>
-FrameSequence::SwapFrame(uint32_t framenum, imgFrame* aFrame)
-{
-  NS_ABORT_IF_FALSE(framenum < mFrames.Length(), "Swapping invalid frame!");
-
-  FrameDataPair ret;
-
-  // Steal the imgFrame.
-  if (framenum < mFrames.Length()) {
-    ret = mFrames[framenum];
-  }
-
-  if (aFrame) {
-    mFrames.ReplaceElementAt(framenum, aFrame);
-  } else {
-    mFrames.RemoveElementAt(framenum);
-  }
-
-  return ret.GetFrame();
-}
-
-size_t
-FrameSequence::SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
-                                                       MallocSizeOf aMallocSizeOf) const
-{
-  size_t n = 0;
-  for (uint32_t i = 0; i < mFrames.Length(); ++i) {
-    FrameDataPair fdp = mFrames.SafeElementAt(i, FrameDataPair());
-    NS_ABORT_IF_FALSE(fdp, "Null frame in frame array!");
-    n += fdp->SizeOfExcludingThisWithComputedFallbackIfHeap(aLocation, aMallocSizeOf);
-  }
-
-  return n;
-}
-
-} // namespace image
-} // namespace mozilla
deleted file mode 100644
--- a/image/src/FrameSequence.h
+++ /dev/null
@@ -1,206 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_imagelib_FrameSequence_h_
-#define mozilla_imagelib_FrameSequence_h_
-
-#include "nsTArray.h"
-#include "mozilla/MemoryReporting.h"
-#include "mozilla/Move.h"
-#include "gfxTypes.h"
-#include "imgFrame.h"
-
-namespace mozilla {
-namespace image {
-
-/**
- * FrameDataPair is a slightly-smart tuple of (frame, raw frame data) where the
- * raw frame data is allowed to be (and is, initially) null.
- *
- * If you call LockAndGetData, you will be able to call GetFrameData() on that
- * instance, and when the FrameDataPair is destructed, the imgFrame lock will
- * be unlocked.
- */
-class FrameDataPair
-{
-public:
-  explicit FrameDataPair(imgFrame* frame)
-    : mFrame(frame)
-    , mFrameData(nullptr)
-  {}
-
-  FrameDataPair()
-    : mFrameData(nullptr)
-  {}
-
-  FrameDataPair(const FrameDataPair& aOther)
-    : mFrame(aOther.mFrame)
-    , mFrameData(nullptr)
-  {}
-
-  FrameDataPair(FrameDataPair&& aOther)
-    : mFrame(Move(aOther.mFrame))
-    , mFrameData(aOther.mFrameData)
-  {
-    aOther.mFrameData = nullptr;
-  }
-
-  ~FrameDataPair()
-  {
-    if (mFrameData) {
-      mFrame->UnlockImageData();
-    }
-  }
-
-  FrameDataPair& operator=(const FrameDataPair& aOther)
-  {
-    if (&aOther != this) {
-      mFrame = aOther.mFrame;
-      mFrameData = nullptr;
-    }
-    return *this;
-  }
-
-  FrameDataPair& operator=(FrameDataPair&& aOther)
-  {
-    MOZ_ASSERT(&aOther != this, "Moving to self");
-    mFrame = Move(aOther.mFrame);
-    mFrameData = aOther.mFrameData;
-    aOther.mFrameData = nullptr;
-    return *this;
-  }
-
-  // Lock the frame and store its mFrameData. The frame will be unlocked (and
-  // deleted) when this FrameDataPair is deleted.
-  void LockAndGetData()
-  {
-    if (mFrame) {
-      if (NS_SUCCEEDED(mFrame->LockImageData())) {
-        if (mFrame->GetIsPaletted()) {
-          mFrameData = reinterpret_cast<uint8_t*>(mFrame->GetPaletteData());
-        } else {
-          mFrameData = mFrame->GetImageData();
-        }
-      }
-    }
-  }
-
-  // Null out this FrameDataPair and return its frame. You must ensure the
-  // frame will be deleted separately.
-  already_AddRefed<imgFrame> Forget()
-  {
-    if (mFrameData) {
-      mFrame->UnlockImageData();
-    }
-
-    mFrameData = nullptr;
-    return mFrame.forget();
-  }
-
-  bool HasFrameData() const
-  {
-    if (mFrameData) {
-      MOZ_ASSERT(!!mFrame);
-    }
-    return !!mFrameData;
-  }
-
-  uint8_t* GetFrameData() const
-  {
-    return mFrameData;
-  }
-
-  already_AddRefed<imgFrame> GetFrame() const
-  {
-    nsRefPtr<imgFrame> frame = mFrame;
-    return frame.forget();
-  }
-
-  // Resets this FrameDataPair to work with a different frame. Takes ownership
-  // of the frame, deleting the old frame (if any).
-  void SetFrame(imgFrame* frame)
-  {
-    if (mFrameData) {
-      mFrame->UnlockImageData();
-    }
-
-    mFrame = frame;
-    mFrameData = nullptr;
-  }
-
-  imgFrame* operator->() const
-  {
-    return mFrame.get();
-  }
-
-  bool operator==(imgFrame* other) const
-  {
-    return mFrame == other;
-  }
-
-  operator bool() const
-  {
-    return mFrame != nullptr;
-  }
-
-private:
-  nsRefPtr<imgFrame> mFrame;
-  uint8_t* mFrameData;
-};
-
-/**
- * FrameSequence stores image frames (and their associated raw data pointers).
- * It is little more than a smart array.
- */
-class FrameSequence
-{
-  ~FrameSequence();
-
-public:
-
-  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(FrameSequence)
-
-  /**
-   * Get the read-only (frame, data) pair at index aIndex.
-   */
-  const FrameDataPair& GetFrame(uint32_t aIndex) const;
-
-  /**
-   * Insert a frame into the array. FrameSequence takes ownership of the frame.
-   */
-  void InsertFrame(uint32_t framenum, imgFrame* aFrame);
-
-  /**
-   * Remove (and delete) the frame at index framenum.
-   */
-  void RemoveFrame(uint32_t framenum);
-
-  /**
-   * Swap aFrame with the frame at sequence framenum, and return that frame.
-   * You take ownership over the frame returned.
-   */
-  already_AddRefed<imgFrame> SwapFrame(uint32_t framenum, imgFrame* aFrame);
-
-  /**
-   * Remove (and delete) all frames.
-   */
-  void ClearFrames();
-
-  /* The total number of frames in this image. */
-  uint32_t GetNumFrames() const;
-
-  size_t SizeOfDecodedWithComputedFallbackIfHeap(gfxMemoryLocation aLocation,
-                                                 MallocSizeOf aMallocSizeOf) const;
-
-private: // data
-  //! All the frames of the image
-  nsTArray<FrameDataPair> mFrames;
-};
-
-} // namespace image
-} // namespace mozilla
-
-#endif /* mozilla_imagelib_FrameSequence_h_ */
--- a/image/src/RasterImage.cpp
+++ b/image/src/RasterImage.cpp
@@ -366,25 +366,16 @@ RasterImage::~RasterImage()
   }
 
   if (mDecoder) {
     // Kill off our decode request, if it's pending.  (If not, this call is
     // harmless.)
     ReentrantMonitorAutoEnter lock(mDecodingMonitor);
     DecodePool::StopDecoding(this);
     mDecoder = nullptr;
-
-    // Unlock the last frame (if we have any). Our invariant is that, while we
-    // have a decoder open, the last frame is always locked.
-    // This would be done in ShutdownDecoder, but since mDecoder is non-null,
-    // we didn't call ShutdownDecoder and we need to do it manually.
-    if (GetNumFrames() > 0) {
-      nsRefPtr<imgFrame> curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
-      curframe->UnlockImageData();
-    }
   }
 
   // Release any HQ scaled frames from the surface cache.
   SurfaceCache::Discard(this);
 
   mAnim = nullptr;
 
   // Total statistics
@@ -1043,28 +1034,30 @@ RasterImage::InternalAddFrameHelper(uint
                                     uint8_t **imageData, uint32_t *imageLength,
                                     uint32_t **paletteData, uint32_t *paletteLength,
                                     imgFrame** aRetFrame)
 {
   NS_ABORT_IF_FALSE(framenum <= GetNumFrames(), "Invalid frame index!");
   if (framenum > GetNumFrames())
     return NS_ERROR_INVALID_ARG;
 
-  nsRefPtr<imgFrame> frame(aFrame);
-
-  // We are in the middle of decoding. This will be unlocked when we finish
-  // decoding or switch to another frame.
-  frame->LockImageData();
+  nsRefPtr<imgFrame> frame = aFrame;
+  RawAccessFrameRef ref = frame->RawAccessRef();
+  if (!ref) {
+    // Probably the OS discarded the frame. Exceedingly unlikely since we just
+    // created it, but it could happen.
+    return NS_ERROR_FAILURE;
+  }
 
   if (paletteData && paletteLength)
     frame->GetPaletteData(paletteData, paletteLength);
 
   frame->GetImageData(imageData, imageLength);
 
-  mFrameBlender.InsertFrame(framenum, frame);
+  mFrameBlender.InsertFrame(framenum, Move(ref));
 
   frame.forget(aRetFrame);
   return NS_OK;
 }
 
 nsresult
 RasterImage::InternalAddFrame(uint32_t framenum,
                               int32_t aX, int32_t aY,
@@ -1091,23 +1084,16 @@ RasterImage::InternalAddFrame(uint32_t f
   nsIntRect frameRect(aX, aY, aWidth, aHeight);
   nsresult rv = frame->InitForDecoder(frameRect, aFormat, aPaletteDepth);
   if (!(mSize.width > 0 && mSize.height > 0))
     NS_WARNING("Shouldn't call InternalAddFrame with zero size");
   if (!NS_SUCCEEDED(rv))
     NS_WARNING("imgFrame::Init should succeed");
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // We know we are in a decoder. Therefore, we must unlock the previous frame
-  // when we move on to decoding into the next frame.
-  if (GetNumFrames() > 0) {
-    nsRefPtr<imgFrame> prevframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
-    prevframe->UnlockImageData();
-  }
-
   if (GetNumFrames() == 0) {
     return InternalAddFrameHelper(framenum, frame, imageData, imageLength,
                                   paletteData, paletteLength, aRetFrame);
   }
 
   if (GetNumFrames() == 1) {
     // Since we're about to add our second frame, initialize animation stuff
     EnsureAnimExists();
@@ -1261,21 +1247,16 @@ RasterImage::EnsureFrame(uint32_t aFrame
     }
     if (*imageData && !paletteData) {
       frame.forget(aRetFrame);
       return NS_OK;
     }
   }
 
   // Not reusable, so replace the frame directly.
-
-  // We know this frame is already locked, because it's the one we're currently
-  // writing to.
-  frame->UnlockImageData();
-
   mFrameBlender.RemoveFrame(aFrameNum);
   nsRefPtr<imgFrame> newFrame(new imgFrame());
   nsIntRect frameRect(aX, aY, aWidth, aHeight);
   nsresult rv = newFrame->InitForDecoder(frameRect, aFormat, aPaletteDepth);
   NS_ENSURE_SUCCESS(rv, rv);
   return InternalAddFrameHelper(aFrameNum, newFrame, imageData, imageLength,
                                 paletteData, paletteLength, aRetFrame);
 }
@@ -1349,18 +1330,17 @@ RasterImage::DecodingComplete()
       firstFrame->SetDiscardable();
     }
   }
 
   // Double-buffer our frame in the multipart case, since we'll start decoding
   // into the first frame again immediately and this produces severe tearing.
   if (mMultipart) {
     if (GetNumFrames() == 1) {
-      mMultipartDecodedFrame = mFrameBlender.SwapFrame(GetCurrentFrameIndex(),
-                                                       mMultipartDecodedFrame);
+      mMultipartDecodedFrame = mFrameBlender.GetFrame(GetCurrentFrameIndex());
     } else {
       // Don't double buffer for animated multipart images. It entails more
       // complexity and it's not really needed since we already are smart about
       // not displaying the still-decoding frame of an animated image. We may
       // have already stored an extra frame, though, so we'll release it here.
       mMultipartDecodedFrame = nullptr;
     }
   }
@@ -1972,24 +1952,16 @@ RasterImage::InitDecoder(bool aDoSizeDec
       break;
     case eDecoderType_icon:
       mDecoder = new nsIconDecoder(*this);
       break;
     default:
       NS_ABORT_IF_FALSE(0, "Shouldn't get here!");
   }
 
-  // If we already have frames, we're probably in the multipart/x-mixed-replace
-  // case. Regardless, we need to lock the last frame. Our invariant is that,
-  // while we have a decoder open, the last frame is always locked.
-  if (GetNumFrames() > 0) {
-    nsRefPtr<imgFrame> curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
-    curframe->LockImageData();
-  }
-
   // Initialize the decoder
   if (!mDecodeRequest) {
     mDecodeRequest = new DecodeRequest(this);
   }
   MOZ_ASSERT(mDecodeRequest->mStatusTracker);
   MOZ_ASSERT(mDecodeRequest->mStatusTracker->GetDecoderObserver());
   mDecoder->SetObserver(mDecodeRequest->mStatusTracker->GetDecoderObserver());
   mDecoder->SetSizeDecode(aDoSizeDecode);
@@ -2055,23 +2027,16 @@ RasterImage::ShutdownDecoder(eShutdownIn
   mDecoder = nullptr;
 
   mFinishing = true;
   mInDecoder = true;
   decoder->Finish(aIntent);
   mInDecoder = false;
   mFinishing = false;
 
-  // Unlock the last frame (if we have any). Our invariant is that, while we
-  // have a decoder open, the last frame is always locked.
-  if (GetNumFrames() > 0) {
-    nsRefPtr<imgFrame> curframe = mFrameBlender.RawGetFrame(GetNumFrames() - 1);
-    curframe->UnlockImageData();
-  }
-
   // Kill off our decode request, if it's pending.  (If not, this call is
   // harmless.)
   DecodePool::StopDecoding(this);
 
   nsresult decoderStatus = decoder->GetDecoderError();
   if (NS_FAILED(decoderStatus)) {
     DoError();
     return decoderStatus;
--- a/image/src/imgFrame.cpp
+++ b/image/src/imgFrame.cpp
@@ -581,18 +581,27 @@ imgFrame::GetStride() const
 
 SurfaceFormat imgFrame::GetFormat() const
 {
   return mFormat;
 }
 
 bool imgFrame::GetNeedsBackground() const
 {
-  // We need a background painted if we have alpha or we're incomplete.
-  return (mFormat == SurfaceFormat::B8G8R8A8 || !ImageComplete());
+  // We need a background painted if we're incomplete.
+  if (!ImageComplete()) {
+    return true;
+  }
+
+  // We need a background painted if we might not be opaque.
+  if (mFormat == SurfaceFormat::B8G8R8A8 && !mHasNoAlpha) {
+    return true;
+  }
+
+  return false;
 }
 
 uint32_t imgFrame::GetImageBytesPerRow() const
 {
   if (mVBuf)
     return mSize.width * BytesPerPixel(mFormat);
 
   if (mPaletteDepth)
@@ -654,16 +663,26 @@ void imgFrame::GetPaletteData(uint32_t *
 uint32_t* imgFrame::GetPaletteData() const
 {
   uint32_t* data;
   uint32_t length;
   GetPaletteData(&data, &length);
   return data;
 }
 
+uint8_t*
+imgFrame::GetRawData() const
+{
+  MOZ_ASSERT(mLockCount, "Should be locked to call GetRawData()");
+  if (mPalettedImageData) {
+    return mPalettedImageData;
+  }
+  return GetImageData();
+}
+
 nsresult imgFrame::LockImageData()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   NS_ABORT_IF_FALSE(mLockCount >= 0, "Unbalanced locks and unlocks");
   if (mLockCount < 0) {
     return NS_ERROR_FAILURE;
   }
--- a/image/src/imgFrame.h
+++ b/image/src/imgFrame.h
@@ -92,16 +92,17 @@ public:
   uint32_t GetImageBytesPerRow() const;
   uint32_t GetImageDataLength() const;
   bool GetIsPaletted() const;
   bool GetHasAlpha() const;
   void GetImageData(uint8_t **aData, uint32_t *length) const;
   uint8_t* GetImageData() const;
   void GetPaletteData(uint32_t **aPalette, uint32_t *length) const;
   uint32_t* GetPaletteData() const;
+  uint8_t* GetRawData() const;
 
   int32_t GetRawTimeout() const;
   void SetRawTimeout(int32_t aTimeout);
 
   int32_t GetFrameDisposalMethod() const;
   void SetFrameDisposalMethod(int32_t aFrameDisposalMethod);
   int32_t GetBlendMethod() const;
   void SetBlendMethod(int32_t aBlendMethod);
--- a/image/src/moz.build
+++ b/image/src/moz.build
@@ -16,17 +16,16 @@ EXPORTS += [
 
 UNIFIED_SOURCES += [
     'ClippedImage.cpp',
     'Decoder.cpp',
     'DiscardTracker.cpp',
     'DynamicImage.cpp',
     'FrameAnimator.cpp',
     'FrameBlender.cpp',
-    'FrameSequence.cpp',
     'FrozenImage.cpp',
     'Image.cpp',
     'ImageFactory.cpp',
     'ImageMetadata.cpp',
     'ImageOps.cpp',
     'ImageWrapper.cpp',
     'imgFrame.cpp',
     'imgTools.cpp',