Bug 1382683 - Part 3. Add gtests for SurfaceFilter/Pipe::WritePixelBlocks. r=tnikkel
authorAndrew Osmond <aosmond@mozilla.com>
Fri, 25 May 2018 06:52:05 -0400
changeset 419871 b37bf166ab83f54292e6a566cd642893d7b45b6b
parent 419870 1f1623675fdcd6a61dbbfb2341e0ba02022a3086
child 419872 a6f3af165d488712c31c2e2f43214c0820c27ace
push id34052
push userccoroiu@mozilla.com
push dateFri, 25 May 2018 17:52:14 +0000
treeherdermozilla-central@94d7f0e1c4d0 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerstnikkel
bugs1382683
milestone62.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 1382683 - Part 3. Add gtests for SurfaceFilter/Pipe::WritePixelBlocks. r=tnikkel
image/test/gtest/TestSurfacePipeIntegration.cpp
image/test/gtest/TestSurfaceSink.cpp
--- a/image/test/gtest/TestSurfacePipeIntegration.cpp
+++ b/image/test/gtest/TestSurfacePipeIntegration.cpp
@@ -196,16 +196,32 @@ TEST_F(ImageSurfacePipeIntegration, Surf
       result = pipe.WriteBuffer(buffer, 0, 100);
       ++count;
     }
     EXPECT_EQ(WriteState::FINISHED, result);
     EXPECT_EQ(100u, count);
     CheckSurfacePipeMethodResults(&pipe, decoder);
   }
 
+  // Test that WritePixelBlocks() gets passed through to the underlying pipeline.
+  {
+    uint32_t count = 0;
+    WriteState result = pipe.WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
+                                                            int32_t aLength) {
+      ++count;
+      EXPECT_EQ(int32_t(100), aLength);
+      memcpy(aBlockStart, buffer, 100 * sizeof(uint32_t));
+      return MakeTuple(int32_t(100), Maybe<WriteState>());
+    });
+
+    EXPECT_EQ(WriteState::FINISHED, result);
+    EXPECT_EQ(100u, count);
+    CheckSurfacePipeMethodResults(&pipe, decoder);
+  }
+
   // Test that WriteEmptyRow() gets passed through to the underlying pipeline.
   {
     uint32_t count = 0;
     WriteState result = WriteState::NEED_MORE_DATA;
     while (result == WriteState::NEED_MORE_DATA) {
       result = pipe.WriteEmptyRow();
       ++count;
     }
@@ -276,16 +292,32 @@ TEST_F(ImageSurfacePipeIntegration, Pale
       result = pipe.WriteBuffer(buffer, 0, 100);
       ++count;
     }
     EXPECT_EQ(WriteState::FINISHED, result);
     EXPECT_EQ(100u, count);
     CheckPalettedSurfacePipeMethodResults(&pipe, decoder);
   }
 
+  // Test that WritePixelBlocks() gets passed through to the underlying pipeline.
+  {
+    uint32_t count = 0;
+    WriteState result = pipe.WritePixelBlocks<uint8_t>([&](uint8_t* aBlockStart,
+                                                           int32_t aLength) {
+      ++count;
+      EXPECT_EQ(int32_t(100), aLength);
+      memcpy(aBlockStart, buffer, 100 * sizeof(uint8_t));
+      return MakeTuple(int32_t(100), Maybe<WriteState>());
+    });
+
+    EXPECT_EQ(WriteState::FINISHED, result);
+    EXPECT_EQ(100u, count);
+    CheckPalettedSurfacePipeMethodResults(&pipe, decoder);
+  }
+
   // Test that WriteEmptyRow() gets passed through to the underlying pipeline.
   {
     uint32_t count = 0;
     WriteState result = WriteState::NEED_MORE_DATA;
     while (result == WriteState::NEED_MORE_DATA) {
       result = pipe.WriteEmptyRow();
       ++count;
     }
--- a/image/test/gtest/TestSurfaceSink.cpp
+++ b/image/test/gtest/TestSurfaceSink.cpp
@@ -597,16 +597,164 @@ TEST(ImageSurfaceSink, SurfaceSinkWriteU
                                                          uint32_t aLength) {
         EXPECT_EQ(100u, aLength );
         memcpy(aRow + 50, buffer, 50 * sizeof(uint32_t));
       });
     });
   });
 }
 
+TEST(ImageSurfaceSink, SurfaceSinkWritePixelBlocks)
+{
+  WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
+    // Create a green buffer the same size as one row of the surface (which is 100x100),
+    // containing 60 pixels of green in the middle and 20 transparent pixels on
+    // either side.
+    uint32_t buffer[100];
+    for (int i = 0; i < 100; ++i) {
+      buffer[i] = 20 <= i && i < 80 ? BGRAColor::Green().AsPixel()
+                                    : BGRAColor::Transparent().AsPixel();
+    }
+
+    uint32_t count = 0;
+    WriteState result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
+                                                              int32_t aLength) {
+      ++count;
+      EXPECT_EQ(int32_t(100), aLength);
+      memcpy(aBlockStart, buffer, 100 * sizeof(uint32_t));
+      return MakeTuple(int32_t(100), Maybe<WriteState>());
+    });
+
+    EXPECT_EQ(WriteState::FINISHED, result);
+    EXPECT_EQ(100u, count);
+
+    AssertCorrectPipelineFinalState(aSink,
+                                    IntRect(0, 0, 100, 100),
+                                    IntRect(0, 0, 100, 100));
+
+    // Check that the generated image is correct.
+    CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
+
+    // Attempt to write more and make sure that nothing gets written.
+    count = 0;
+    result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
+                                                   int32_t aLength) {
+      count++;
+      for (int32_t i = 0; i < aLength; ++i) {
+        aBlockStart[i] = BGRAColor::Red().AsPixel();
+      }
+      return MakeTuple(aLength, Maybe<WriteState>());
+    });
+
+    EXPECT_EQ(WriteState::FINISHED, result);
+    EXPECT_EQ(0u, count);
+    EXPECT_TRUE(aSink->IsSurfaceFinished());
+
+    // Check that the generated image is still correct.
+    CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
+  });
+}
+
+TEST(ImageSurfaceSink, SurfaceSinkWritePixelBlocksPartialRow)
+{
+  WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
+    // Create a green buffer the same size as one row of the surface (which is 100x100),
+    // containing 60 pixels of green in the middle and 20 transparent pixels on
+    // either side.
+    uint32_t buffer[100];
+    for (int i = 0; i < 100; ++i) {
+      buffer[i] = 20 <= i && i < 80 ? BGRAColor::Green().AsPixel()
+                                    : BGRAColor::Transparent().AsPixel();
+    }
+
+    // Write the first 99 rows of our 100x100 surface and verify that even
+    // though our lambda will yield pixels forever, only one row is written per
+    // call to WritePixelsToRow().
+    for (int row = 0; row < 99; ++row) {
+      for (int32_t written = 0; written < 100; ) {
+        WriteState result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
+                                                                  int32_t aLength) {
+          // When we write the final block of pixels, it will request we start
+          // another row. We should abort at that point.
+          if (aLength == int32_t(100) && written == int32_t(100)) {
+            return MakeTuple(int32_t(0), Some(WriteState::NEED_MORE_DATA));
+          }
+
+          // It should always request enough data to fill the row. So it should
+          // request 100, 75, 50, and finally 25 pixels.
+          EXPECT_EQ(int32_t(100) - written, aLength);
+
+          // Only write one quarter of the pixels for the row.
+          memcpy(aBlockStart, &buffer[written], 25 * sizeof(uint32_t));
+          written += 25;
+
+          // We've written the last pixels remaining for the row.
+          if (written == int32_t(100)) {
+            return MakeTuple(int32_t(25), Maybe<WriteState>());
+          }
+
+          // We've written another quarter of the row but not yet all of it.
+          return MakeTuple(int32_t(25), Some(WriteState::NEED_MORE_DATA));
+        });
+
+        EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
+      }
+
+      EXPECT_FALSE(aSink->IsSurfaceFinished());
+
+      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
+      EXPECT_TRUE(invalidRect.isSome());
+      EXPECT_EQ(IntRect(0, row, 100, 1), invalidRect->mInputSpaceRect);
+      EXPECT_EQ(IntRect(0, row, 100, 1), invalidRect->mOutputSpaceRect);
+
+      CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, row + 1));
+    }
+
+    // Write the final line, which should finish the surface.
+    uint32_t count = 0;
+    WriteState result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
+                                                              int32_t aLength) {
+      ++count;
+      EXPECT_EQ(int32_t(100), aLength);
+      memcpy(aBlockStart, buffer, 100 * sizeof(uint32_t));
+      return MakeTuple(int32_t(100), Maybe<WriteState>());
+    });
+
+    EXPECT_EQ(WriteState::FINISHED, result);
+    EXPECT_EQ(1u, count);
+
+    // Note that the final invalid rect we expect here is only the last row;
+    // that's because we called TakeInvalidRect() repeatedly in the loop above.
+    AssertCorrectPipelineFinalState(aSink,
+                                    IntRect(0, 99, 100, 1),
+                                    IntRect(0, 99, 100, 1));
+
+    // Check that the generated image is correct.
+    CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
+
+    // Attempt to write more and make sure that nothing gets written.
+    count = 0;
+    result = aSink->WritePixelBlocks<uint32_t>([&](uint32_t* aBlockStart,
+                                                   int32_t aLength) {
+      count++;
+      for (int32_t i = 0; i < aLength; ++i) {
+        aBlockStart[i] = BGRAColor::Red().AsPixel();
+      }
+      return MakeTuple(aLength, Maybe<WriteState>());
+    });
+
+    EXPECT_EQ(WriteState::FINISHED, result);
+    EXPECT_EQ(0u, count);
+    EXPECT_TRUE(aSink->IsSurfaceFinished());
+
+    // Check that the generated image is still correct.
+    CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
+  });
+}
+
 TEST(ImageSurfaceSink, SurfaceSinkProgressivePasses)
 {
   WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
     {
       // Fill the image with a first pass of red.
       uint32_t count = 0;
       auto result = aSink->WritePixels<uint32_t>([&]() {
         ++count;