Bug 1465619 - Part 14. Add gtests for AnimationFrameRecyclingQueue. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Wed, 06 Jun 2018 10:31:53 -0400
changeset 490716 2ce8f6d1a64ef8ee845c595bc441234af72422fe
parent 490715 6bf7e20ce8fcd856eb8b11853ec94fb0172a9597
child 490717 f0f7573deea111d97bc96aa6b33e2518ee89da3a
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewerstnikkel
bugs1465619
milestone65.0a1
Bug 1465619 - Part 14. Add gtests for AnimationFrameRecyclingQueue. r=tnikkel Differential Revision: https://phabricator.services.mozilla.com/D7519
image/test/gtest/TestAnimationFrameBuffer.cpp
--- a/image/test/gtest/TestAnimationFrameBuffer.cpp
+++ b/image/test/gtest/TestAnimationFrameBuffer.cpp
@@ -85,18 +85,43 @@ VerifyInsertInternal(AnimationFrameBuffe
   EXPECT_EQ(aFrame, frame.get());
 }
 
 static void
 VerifyAdvance(AnimationFrameBuffer& aQueue,
               size_t aExpectedFrame,
               bool aExpectedRestartDecoder)
 {
+  RefPtr<imgFrame> oldFrame;
+  size_t totalRecycled;
+  if (aQueue.IsRecycling()) {
+    AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    oldFrame = queue.Get(queue.Displayed(), false);
+    totalRecycled = queue.Recycle().size();
+  }
+
   bool restartDecoder = aQueue.AdvanceTo(aExpectedFrame);
   EXPECT_EQ(aExpectedRestartDecoder, restartDecoder);
+
+  if (aQueue.IsRecycling()) {
+    const AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    if (oldFrame->ShouldRecycle()) {
+      EXPECT_EQ(oldFrame.get(), queue.Recycle().back().mFrame.get());
+      EXPECT_FALSE(queue.Recycle().back().mDirtyRect.IsEmpty());
+      EXPECT_FALSE(queue.Recycle().back().mRecycleRect.IsEmpty());
+      EXPECT_EQ(totalRecycled + 1, queue.Recycle().size());
+    } else {
+      EXPECT_EQ(totalRecycled, queue.Recycle().size());
+      if (!queue.Recycle().empty()) {
+        EXPECT_NE(oldFrame.get(), queue.Recycle().back().mFrame.get());
+      }
+    }
+  }
 }
 
 static void
 VerifyInsertAndAdvance(AnimationFrameBuffer& aQueue,
                        size_t aExpectedFrame,
                        AnimationFrameBuffer::InsertStatus aExpectedStatus)
 {
   // Insert the decoded frame.
@@ -113,18 +138,30 @@ VerifyInsertAndAdvance(AnimationFrameBuf
   VerifyAdvance(aQueue, aExpectedFrame, expectedRestartDecoder);
 }
 
 static void
 VerifyMarkComplete(AnimationFrameBuffer& aQueue,
                    bool aExpectedContinue,
                    const IntRect& aRefreshArea = IntRect(0, 0, 1, 1))
 {
+  if (aQueue.IsRecycling() && !aQueue.SizeKnown()) {
+    const AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    EXPECT_TRUE(queue.FirstFrameRefreshArea().IsEmpty());
+  }
+
   bool keepDecoding = aQueue.MarkComplete(aRefreshArea);
   EXPECT_EQ(aExpectedContinue, keepDecoding);
+
+  if (aQueue.IsRecycling()) {
+    const AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    EXPECT_EQ(aRefreshArea, queue.FirstFrameRefreshArea());
+  }
 }
 
 static void
 VerifyInsert(AnimationFrameBuffer& aQueue,
              AnimationFrameBuffer::InsertStatus aExpectedStatus)
 {
   RefPtr<imgFrame> frame = CreateEmptyFrame();
   AnimationFrameBuffer::InsertStatus status =
@@ -152,16 +189,22 @@ VerifyReset(AnimationFrameBuffer& aQueue
   } else {
     const AnimationFrameDiscardingQueue& queue =
       *static_cast<AnimationFrameDiscardingQueue*>(&aQueue);
     EXPECT_EQ(size_t(0), queue.PendingInsert());
     EXPECT_EQ(size_t(0), queue.Display().size());
     EXPECT_EQ(aFirstFrame, queue.FirstFrame());
     EXPECT_EQ(nullptr, aQueue.Get(0, false));
   }
+
+  if (aQueue.IsRecycling()) {
+    const AnimationFrameRecyclingQueue& queue =
+      *static_cast<AnimationFrameRecyclingQueue*>(&aQueue);
+    EXPECT_EQ(size_t(0), queue.Recycle().size());
+  }
 }
 
 class ImageAnimationFrameBuffer : public ::testing::Test
 {
 public:
   ImageAnimationFrameBuffer()
   { }
 
@@ -510,16 +553,52 @@ TEST_F(ImageAnimationFrameBuffer, Discar
   const size_t kStartFrame = 0;
   AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
   PrepareForDiscardingQueue(retained);
   const imgFrame* firstFrame = retained.Frames()[0].get();
   AnimationFrameDiscardingQueue buffer(std::move(retained));
   TestDiscardingQueueLoop(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
 }
 
+TEST_F(ImageAnimationFrameBuffer, RecyclingLoop)
+{
+  const size_t kThreshold = 5;
+  const size_t kBatch = 2;
+  const size_t kStartFrame = 0;
+  AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
+  PrepareForDiscardingQueue(retained);
+  const imgFrame* firstFrame = retained.Frames()[0].get();
+  AnimationFrameRecyclingQueue buffer(std::move(retained));
+
+  // We should not start with any recycled frames.
+  ASSERT_TRUE(buffer.Recycle().empty());
+
+  TestDiscardingQueueLoop(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
+
+  // All the frames we inserted should have been recycleable.
+  ASSERT_FALSE(buffer.Recycle().empty());
+  while (!buffer.Recycle().empty()) {
+    IntRect expectedRect = buffer.Recycle().front().mRecycleRect;
+    RefPtr<imgFrame> expectedFrame = buffer.Recycle().front().mFrame;
+    EXPECT_FALSE(expectedRect.IsEmpty());
+    EXPECT_TRUE(expectedFrame.get() != nullptr);
+
+    IntRect gotRect;
+    RawAccessFrameRef gotFrame = buffer.RecycleFrame(gotRect);
+    EXPECT_EQ(expectedFrame.get(), gotFrame.get());
+    EXPECT_EQ(expectedRect, gotRect);
+  }
+
+  // Trying to pull a recycled frame when we have nothing should be safe too.
+  IntRect gotRect;
+  RawAccessFrameRef gotFrame = buffer.RecycleFrame(gotRect);
+  EXPECT_TRUE(gotFrame.get() == nullptr);
+  EXPECT_TRUE(gotRect.IsEmpty());
+}
+
 static void TestDiscardingQueueReset(AnimationFrameDiscardingQueue& aQueue,
                                      const imgFrame* aFirstFrame,
                                      size_t aThreshold,
                                      size_t aBatch,
                                      size_t aStartFrame)
 {
   // We should be advanced right up to the last decoded frame.
   EXPECT_TRUE(aQueue.MayDiscard());
@@ -542,8 +621,20 @@ TEST_F(ImageAnimationFrameBuffer, Discar
   const size_t kBatch = 3;
   const size_t kStartFrame = 0;
   AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
   PrepareForDiscardingQueue(retained);
   const imgFrame* firstFrame = retained.Frames()[0].get();
   AnimationFrameDiscardingQueue buffer(std::move(retained));
   TestDiscardingQueueReset(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
 }
+
+TEST_F(ImageAnimationFrameBuffer, RecyclingReset)
+{
+  const size_t kThreshold = 8;
+  const size_t kBatch = 3;
+  const size_t kStartFrame = 0;
+  AnimationFrameRetainedBuffer retained(kThreshold, kBatch, kStartFrame);
+  PrepareForDiscardingQueue(retained);
+  const imgFrame* firstFrame = retained.Frames()[0].get();
+  AnimationFrameRecyclingQueue buffer(std::move(retained));
+  TestDiscardingQueueReset(buffer, firstFrame, kThreshold, kBatch, kStartFrame);
+}