tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TestSurfaceSink.cpp (37358B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "gtest/gtest.h"
      8 
      9 #include "mozilla/gfx/2D.h"
     10 #include "Common.h"
     11 #include "Decoder.h"
     12 #include "DecoderFactory.h"
     13 #include "SourceBuffer.h"
     14 #include "SurfacePipe.h"
     15 
     16 using namespace mozilla;
     17 using namespace mozilla::gfx;
     18 using namespace mozilla::image;
     19 
     20 enum class Orient { NORMAL, FLIP_VERTICALLY };
     21 
     22 static void InitializeRowBuffer(uint32_t* aBuffer, size_t aSize,
     23                                size_t aStartPixel, size_t aEndPixel,
     24                                uint32_t aSetPixel) {
     25  uint32_t transparentPixel = BGRAColor::Transparent().AsPixel();
     26  for (size_t i = 0; i < aStartPixel && i < aSize; ++i) {
     27    aBuffer[i] = transparentPixel;
     28  }
     29  for (size_t i = aStartPixel; i < aEndPixel && i < aSize; ++i) {
     30    aBuffer[i] = aSetPixel;
     31  }
     32  for (size_t i = aEndPixel; i < aSize; ++i) {
     33    aBuffer[i] = transparentPixel;
     34  }
     35 }
     36 
     37 template <Orient Orientation, typename Func>
     38 void WithSurfaceSink(Func aFunc) {
     39  RefPtr<image::Decoder> decoder = CreateTrivialDecoder();
     40  ASSERT_TRUE(decoder != nullptr);
     41 
     42  const bool flipVertically = Orientation == Orient::FLIP_VERTICALLY;
     43 
     44  WithFilterPipeline(decoder, std::forward<Func>(aFunc),
     45                     SurfaceConfig{decoder, IntSize(100, 100),
     46                                   SurfaceFormat::OS_RGBA, flipVertically});
     47 }
     48 
     49 void ResetForNextPass(SurfaceFilter* aSink) {
     50  aSink->ResetToFirstRow();
     51  EXPECT_FALSE(aSink->IsSurfaceFinished());
     52  Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
     53  EXPECT_TRUE(invalidRect.isNothing());
     54 }
     55 
     56 template <typename WriteFunc, typename CheckFunc>
     57 void DoCheckIterativeWrite(SurfaceFilter* aSink, WriteFunc aWriteFunc,
     58                           CheckFunc aCheckFunc) {
     59  // Write the buffer to successive rows until every row of the surface
     60  // has been written.
     61  uint32_t row = 0;
     62  WriteState result = WriteState::NEED_MORE_DATA;
     63  while (result == WriteState::NEED_MORE_DATA) {
     64    result = aWriteFunc(row);
     65    ++row;
     66  }
     67  EXPECT_EQ(WriteState::FINISHED, result);
     68  EXPECT_EQ(100u, row);
     69 
     70  AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 100),
     71                                  IntRect(0, 0, 100, 100));
     72 
     73  // Check that the generated image is correct.
     74  aCheckFunc();
     75 }
     76 
     77 template <typename WriteFunc>
     78 void CheckIterativeWrite(image::Decoder* aDecoder, SurfaceSink* aSink,
     79                         const IntRect& aOutputRect, WriteFunc aWriteFunc) {
     80  // Ignore the row passed to WriteFunc, since no callers use it.
     81  auto writeFunc = [&](uint32_t) { return aWriteFunc(); };
     82 
     83  DoCheckIterativeWrite(aSink, writeFunc,
     84                        [&] { CheckGeneratedImage(aDecoder, aOutputRect); });
     85 }
     86 
     87 TEST(ImageSurfaceSink, SurfaceSinkInitialization)
     88 {
     89  WithSurfaceSink<Orient::NORMAL>(
     90      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
     91        // Check initial state.
     92        EXPECT_FALSE(aSink->IsSurfaceFinished());
     93        Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
     94        EXPECT_TRUE(invalidRect.isNothing());
     95 
     96        // Check that the surface is zero-initialized. We verify this by calling
     97        // CheckGeneratedImage() and telling it that we didn't write to the
     98        // surface anyway (i.e., we wrote to the empty rect); it will then
     99        // expect the entire surface to be transparent, which is what it should
    100        // be if it was zero-initialied.
    101        CheckGeneratedImage(aDecoder, IntRect(0, 0, 0, 0));
    102      });
    103 }
    104 
    105 TEST(ImageSurfaceSink, SurfaceSinkWritePixels)
    106 {
    107  WithSurfaceSink<Orient::NORMAL>(
    108      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
    109        CheckWritePixels(aDecoder, aSink);
    110      });
    111 }
    112 
    113 TEST(ImageSurfaceSink, SurfaceSinkWritePixelsFinish)
    114 {
    115  WithSurfaceSink<Orient::NORMAL>(
    116      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
    117        // Write nothing into the surface; just finish immediately.
    118        uint32_t count = 0;
    119        auto result = aSink->WritePixels<uint32_t>([&]() {
    120          count++;
    121          return AsVariant(WriteState::FINISHED);
    122        });
    123        EXPECT_EQ(WriteState::FINISHED, result);
    124        EXPECT_EQ(1u, count);
    125 
    126        AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 100),
    127                                        IntRect(0, 0, 100, 100));
    128 
    129        // Attempt to write more and make sure that nothing gets written.
    130        count = 0;
    131        result = aSink->WritePixels<uint32_t>([&]() {
    132          count++;
    133          return AsVariant(BGRAColor::Red().AsPixel());
    134        });
    135        EXPECT_EQ(WriteState::FINISHED, result);
    136        EXPECT_EQ(0u, count);
    137        EXPECT_TRUE(aSink->IsSurfaceFinished());
    138 
    139        // Check that the generated image is correct.
    140        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    141        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    142        EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Transparent()));
    143      });
    144 }
    145 
    146 TEST(ImageSurfaceSink, SurfaceSinkWritePixelsEarlyExit)
    147 {
    148  auto checkEarlyExit = [](image::Decoder* aDecoder, SurfaceSink* aSink,
    149                           WriteState aState) {
    150    // Write half a row of green pixels and then exit early with |aState|. If
    151    // the lambda keeps getting called, we'll write red pixels, which will cause
    152    // the test to fail.
    153    uint32_t count = 0;
    154    auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    155      if (count == 50) {
    156        return AsVariant(aState);
    157      }
    158      return count++ < 50 ? AsVariant(BGRAColor::Green().AsPixel())
    159                          : AsVariant(BGRAColor::Red().AsPixel());
    160    });
    161 
    162    EXPECT_EQ(aState, result);
    163    EXPECT_EQ(50u, count);
    164    CheckGeneratedImage(aDecoder, IntRect(0, 0, 50, 1));
    165 
    166    if (aState != WriteState::FINISHED) {
    167      // We should still be able to write more at this point.
    168      EXPECT_FALSE(aSink->IsSurfaceFinished());
    169 
    170      // Verify that we can resume writing. We'll finish up the same row.
    171      count = 0;
    172      result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    173        if (count == 50) {
    174          return AsVariant(WriteState::NEED_MORE_DATA);
    175        }
    176        ++count;
    177        return AsVariant(BGRAColor::Green().AsPixel());
    178      });
    179 
    180      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    181      EXPECT_EQ(50u, count);
    182      EXPECT_FALSE(aSink->IsSurfaceFinished());
    183      CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, 1));
    184 
    185      return;
    186    }
    187 
    188    // We should've finished the surface at this point.
    189    AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 100),
    190                                    IntRect(0, 0, 100, 100));
    191 
    192    // Attempt to write more and make sure that nothing gets written.
    193    count = 0;
    194    result = aSink->WritePixels<uint32_t>([&] {
    195      count++;
    196      return AsVariant(BGRAColor::Red().AsPixel());
    197    });
    198 
    199    EXPECT_EQ(WriteState::FINISHED, result);
    200    EXPECT_EQ(0u, count);
    201    EXPECT_TRUE(aSink->IsSurfaceFinished());
    202 
    203    // Check that the generated image is still correct.
    204    CheckGeneratedImage(aDecoder, IntRect(0, 0, 50, 1));
    205  };
    206 
    207  WithSurfaceSink<Orient::NORMAL>(
    208      [&](image::Decoder* aDecoder, SurfaceSink* aSink) {
    209        checkEarlyExit(aDecoder, aSink, WriteState::NEED_MORE_DATA);
    210      });
    211 
    212  WithSurfaceSink<Orient::NORMAL>(
    213      [&](image::Decoder* aDecoder, SurfaceSink* aSink) {
    214        checkEarlyExit(aDecoder, aSink, WriteState::FAILURE);
    215      });
    216 
    217  WithSurfaceSink<Orient::NORMAL>(
    218      [&](image::Decoder* aDecoder, SurfaceSink* aSink) {
    219        checkEarlyExit(aDecoder, aSink, WriteState::FINISHED);
    220      });
    221 }
    222 
    223 TEST(ImageSurfaceSink, SurfaceSinkWritePixelsToRow)
    224 {
    225  WithSurfaceSink<Orient::NORMAL>([](image::Decoder* aDecoder,
    226                                     SurfaceSink* aSink) {
    227    // Write the first 99 rows of our 100x100 surface and verify that even
    228    // though our lambda will yield pixels forever, only one row is written
    229    // per call to WritePixelsToRow().
    230    for (int row = 0; row < 99; ++row) {
    231      uint32_t count = 0;
    232      WriteState result = aSink->WritePixelsToRow<uint32_t>([&] {
    233        ++count;
    234        return AsVariant(BGRAColor::Green().AsPixel());
    235      });
    236 
    237      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    238      EXPECT_EQ(100u, count);
    239      EXPECT_FALSE(aSink->IsSurfaceFinished());
    240 
    241      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    242      EXPECT_TRUE(invalidRect.isSome());
    243      EXPECT_EQ(OrientedIntRect(0, row, 100, 1), invalidRect->mInputSpaceRect);
    244      EXPECT_EQ(OrientedIntRect(0, row, 100, 1), invalidRect->mOutputSpaceRect);
    245 
    246      CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, row + 1));
    247    }
    248 
    249    // Write the final line, which should finish the surface.
    250    uint32_t count = 0;
    251    WriteState result = aSink->WritePixelsToRow<uint32_t>([&] {
    252      ++count;
    253      return AsVariant(BGRAColor::Green().AsPixel());
    254    });
    255 
    256    EXPECT_EQ(WriteState::FINISHED, result);
    257    EXPECT_EQ(100u, count);
    258 
    259    // Note that the final invalid rect we expect here is only the last row;
    260    // that's because we called TakeInvalidRect() repeatedly in the loop
    261    // above.
    262    AssertCorrectPipelineFinalState(aSink, IntRect(0, 99, 100, 1),
    263                                    IntRect(0, 99, 100, 1));
    264 
    265    // Check that the generated image is correct.
    266    CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, 100));
    267 
    268    // Attempt to write more and make sure that nothing gets written.
    269    count = 0;
    270    result = aSink->WritePixelsToRow<uint32_t>([&] {
    271      count++;
    272      return AsVariant(BGRAColor::Red().AsPixel());
    273    });
    274 
    275    EXPECT_EQ(WriteState::FINISHED, result);
    276    EXPECT_EQ(0u, count);
    277    EXPECT_TRUE(aSink->IsSurfaceFinished());
    278 
    279    // Check that the generated image is still correct.
    280    CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, 100));
    281  });
    282 }
    283 
    284 TEST(ImageSurfaceSink, SurfaceSinkWritePixelsToRowEarlyExit)
    285 {
    286  auto checkEarlyExit = [](image::Decoder* aDecoder, SurfaceSink* aSink,
    287                           WriteState aState) {
    288    // Write half a row of green pixels and then exit early with |aState|. If
    289    // the lambda keeps getting called, we'll write red pixels, which will cause
    290    // the test to fail.
    291    uint32_t count = 0;
    292    auto result =
    293        aSink->WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
    294          if (count == 50) {
    295            return AsVariant(aState);
    296          }
    297          return count++ < 50 ? AsVariant(BGRAColor::Green().AsPixel())
    298                              : AsVariant(BGRAColor::Red().AsPixel());
    299        });
    300 
    301    EXPECT_EQ(aState, result);
    302    EXPECT_EQ(50u, count);
    303    CheckGeneratedImage(aDecoder, IntRect(0, 0, 50, 1));
    304 
    305    if (aState != WriteState::FINISHED) {
    306      // We should still be able to write more at this point.
    307      EXPECT_FALSE(aSink->IsSurfaceFinished());
    308 
    309      // Verify that we can resume the same row and still stop at the end.
    310      count = 0;
    311      WriteState result = aSink->WritePixelsToRow<uint32_t>([&] {
    312        ++count;
    313        return AsVariant(BGRAColor::Green().AsPixel());
    314      });
    315 
    316      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    317      EXPECT_EQ(50u, count);
    318      EXPECT_FALSE(aSink->IsSurfaceFinished());
    319      CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, 1));
    320 
    321      return;
    322    }
    323 
    324    // We should've finished the surface at this point.
    325    AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 100),
    326                                    IntRect(0, 0, 100, 100));
    327 
    328    // Attempt to write more and make sure that nothing gets written.
    329    count = 0;
    330    result = aSink->WritePixelsToRow<uint32_t>([&] {
    331      count++;
    332      return AsVariant(BGRAColor::Red().AsPixel());
    333    });
    334 
    335    EXPECT_EQ(WriteState::FINISHED, result);
    336    EXPECT_EQ(0u, count);
    337    EXPECT_TRUE(aSink->IsSurfaceFinished());
    338 
    339    // Check that the generated image is still correct.
    340    CheckGeneratedImage(aDecoder, IntRect(0, 0, 50, 1));
    341  };
    342 
    343  WithSurfaceSink<Orient::NORMAL>(
    344      [&](image::Decoder* aDecoder, SurfaceSink* aSink) {
    345        checkEarlyExit(aDecoder, aSink, WriteState::NEED_MORE_DATA);
    346      });
    347 
    348  WithSurfaceSink<Orient::NORMAL>(
    349      [&](image::Decoder* aDecoder, SurfaceSink* aSink) {
    350        checkEarlyExit(aDecoder, aSink, WriteState::FAILURE);
    351      });
    352 
    353  WithSurfaceSink<Orient::NORMAL>(
    354      [&](image::Decoder* aDecoder, SurfaceSink* aSink) {
    355        checkEarlyExit(aDecoder, aSink, WriteState::FINISHED);
    356      });
    357 }
    358 
    359 TEST(ImageSurfaceSink, SurfaceSinkWriteBuffer)
    360 {
    361  WithSurfaceSink<Orient::NORMAL>(
    362      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
    363        // Create a green buffer the same size as one row of the surface (which
    364        // is 100x100), containing 60 pixels of green in the middle and 20
    365        // transparent pixels on either side.
    366        uint32_t buffer[100];
    367        InitializeRowBuffer(buffer, 100, 20, 80, BGRAColor::Green().AsPixel());
    368 
    369        // Write the buffer to every row of the surface and check that the
    370        // generated image is correct.
    371        CheckIterativeWrite(aDecoder, aSink, IntRect(20, 0, 60, 100),
    372                            [&] { return aSink->WriteBuffer(buffer); });
    373      });
    374 }
    375 
    376 TEST(ImageSurfaceSink, SurfaceSinkWriteBufferPartialRow)
    377 {
    378  WithSurfaceSink<Orient::NORMAL>(
    379      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
    380        // Create a buffer the same size as one row of the surface, containing
    381        // all green pixels.
    382        uint32_t buffer[100];
    383        for (int i = 0; i < 100; ++i) {
    384          buffer[i] = BGRAColor::Green().AsPixel();
    385        }
    386 
    387        // Write the buffer to the middle 60 pixels of every row of the surface
    388        // and check that the generated image is correct.
    389        CheckIterativeWrite(aDecoder, aSink, IntRect(20, 0, 60, 100),
    390                            [&] { return aSink->WriteBuffer(buffer, 20, 60); });
    391      });
    392 }
    393 
    394 TEST(ImageSurfaceSink, SurfaceSinkWriteBufferPartialRowStartColOverflow)
    395 {
    396  WithSurfaceSink<Orient::NORMAL>([](image::Decoder* aDecoder,
    397                                     SurfaceSink* aSink) {
    398    // Create a buffer the same size as one row of the surface, containing all
    399    // green pixels.
    400    uint32_t buffer[100];
    401    for (int i = 0; i < 100; ++i) {
    402      buffer[i] = BGRAColor::Green().AsPixel();
    403    }
    404 
    405    {
    406      // Write the buffer to successive rows until every row of the surface
    407      // has been written. We place the start column beyond the end of the row,
    408      // which will prevent us from writing anything, so we check that the
    409      // generated image is entirely transparent.
    410      CheckIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0),
    411                          [&] { return aSink->WriteBuffer(buffer, 100, 100); });
    412    }
    413 
    414    ResetForNextPass(aSink);
    415 
    416    {
    417      // Write the buffer to successive rows until every row of the surface
    418      // has been written. We use column 50 as the start column, but we still
    419      // write the buffer, which means we overflow the right edge of the surface
    420      // by 50 pixels. We check that the left half of the generated image is
    421      // transparent and the right half is green.
    422      CheckIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100),
    423                          [&] { return aSink->WriteBuffer(buffer, 50, 100); });
    424    }
    425  });
    426 }
    427 
    428 TEST(ImageSurfaceSink, SurfaceSinkWriteBufferPartialRowBufferOverflow)
    429 {
    430  WithSurfaceSink<Orient::NORMAL>([](image::Decoder* aDecoder,
    431                                     SurfaceSink* aSink) {
    432    // Create a buffer twice as large as a row of the surface. The first half
    433    // (which is as large as a row of the image) will contain green pixels,
    434    // while the second half will contain red pixels.
    435    uint32_t buffer[200];
    436    for (int i = 0; i < 200; ++i) {
    437      buffer[i] =
    438          i < 100 ? BGRAColor::Green().AsPixel() : BGRAColor::Red().AsPixel();
    439    }
    440 
    441    {
    442      // Write the buffer to successive rows until every row of the surface has
    443      // been written. The buffer extends 100 pixels to the right of a row of
    444      // the surface, but bounds checking will prevent us from overflowing the
    445      // buffer. We check that the generated image is entirely green since the
    446      // pixels on the right side of the buffer shouldn't have been written to
    447      // the surface.
    448      CheckIterativeWrite(aDecoder, aSink, IntRect(0, 0, 100, 100),
    449                          [&] { return aSink->WriteBuffer(buffer, 0, 200); });
    450    }
    451 
    452    ResetForNextPass(aSink);
    453 
    454    {
    455      // Write from the buffer to the middle of each row of the surface. That
    456      // means that the left side of each row should be transparent, since we
    457      // didn't write anything there. A buffer overflow would cause us to write
    458      // buffer contents into the left side of each row. We check that the
    459      // generated image is transparent on the left side and green on the right.
    460      CheckIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100),
    461                          [&] { return aSink->WriteBuffer(buffer, 50, 200); });
    462    }
    463  });
    464 }
    465 
    466 TEST(ImageSurfaceSink, SurfaceSinkWriteBufferFromNullSource)
    467 {
    468  WithSurfaceSink<Orient::NORMAL>(
    469      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
    470        // Calling WriteBuffer() with a null pointer should fail without making
    471        // any changes to the surface.
    472        uint32_t* nullBuffer = nullptr;
    473        WriteState result = aSink->WriteBuffer(nullBuffer);
    474 
    475        EXPECT_EQ(WriteState::FAILURE, result);
    476        EXPECT_FALSE(aSink->IsSurfaceFinished());
    477        Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    478        EXPECT_TRUE(invalidRect.isNothing());
    479 
    480        // Check that nothing got written to the surface.
    481        CheckGeneratedImage(aDecoder, IntRect(0, 0, 0, 0));
    482      });
    483 }
    484 
    485 TEST(ImageSurfaceSink, SurfaceSinkWriteEmptyRow)
    486 {
    487  WithSurfaceSink<Orient::NORMAL>([](image::Decoder* aDecoder,
    488                                     SurfaceSink* aSink) {
    489    {
    490      // Write an empty row to each row of the surface. We check that the
    491      // generated image is entirely transparent.
    492      CheckIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0),
    493                          [&] { return aSink->WriteEmptyRow(); });
    494    }
    495 
    496    ResetForNextPass(aSink);
    497 
    498    {
    499      // Write a partial row before we begin calling WriteEmptyRow(). We check
    500      // that the generated image is entirely transparent, which is to be
    501      // expected since WriteEmptyRow() overwrites the current row even if some
    502      // data has already been written to it.
    503      uint32_t count = 0;
    504      auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    505        if (count == 50) {
    506          return AsVariant(WriteState::NEED_MORE_DATA);
    507        }
    508        ++count;
    509        return AsVariant(BGRAColor::Green().AsPixel());
    510      });
    511 
    512      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    513      EXPECT_EQ(50u, count);
    514      EXPECT_FALSE(aSink->IsSurfaceFinished());
    515 
    516      CheckIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0),
    517                          [&] { return aSink->WriteEmptyRow(); });
    518    }
    519 
    520    ResetForNextPass(aSink);
    521 
    522    {
    523      // Create a buffer the same size as one row of the surface, containing all
    524      // green pixels.
    525      uint32_t buffer[100];
    526      for (int i = 0; i < 100; ++i) {
    527        buffer[i] = BGRAColor::Green().AsPixel();
    528      }
    529 
    530      // Write an empty row to the middle 60 rows of the surface. The first 20
    531      // and last 20 rows will be green. (We need to use DoCheckIterativeWrite()
    532      // here because we need a custom function to check the output, since it
    533      // can't be described by a simple rect.)
    534      auto writeFunc = [&](uint32_t aRow) {
    535        if (aRow < 20 || aRow >= 80) {
    536          return aSink->WriteBuffer(buffer);
    537        } else {
    538          return aSink->WriteEmptyRow();
    539        }
    540      };
    541 
    542      auto checkFunc = [&] {
    543        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    544        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    545 
    546        EXPECT_TRUE(RowsAreSolidColor(surface, 0, 20, BGRAColor::Green()));
    547        EXPECT_TRUE(
    548            RowsAreSolidColor(surface, 20, 60, BGRAColor::Transparent()));
    549        EXPECT_TRUE(RowsAreSolidColor(surface, 80, 20, BGRAColor::Green()));
    550      };
    551 
    552      DoCheckIterativeWrite(aSink, writeFunc, checkFunc);
    553    }
    554  });
    555 }
    556 
    557 TEST(ImageSurfaceSink, SurfaceSinkWriteUnsafeComputedRow)
    558 {
    559  WithSurfaceSink<Orient::NORMAL>(
    560      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
    561        // Create a green buffer the same size as one row of the surface.
    562        uint32_t buffer[100];
    563        for (int i = 0; i < 100; ++i) {
    564          buffer[i] = BGRAColor::Green().AsPixel();
    565        }
    566 
    567        // Write the buffer to successive rows until every row of the surface
    568        // has been written. We only write to the right half of each row, so we
    569        // check that the left side of the generated image is transparent and
    570        // the right side is green.
    571        CheckIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100), [&] {
    572          return aSink->WriteUnsafeComputedRow<uint32_t>(
    573              [&](uint32_t* aRow, uint32_t aLength) {
    574                EXPECT_EQ(100u, aLength);
    575                memcpy(aRow + 50, buffer, 50 * sizeof(uint32_t));
    576              });
    577        });
    578      });
    579 }
    580 
    581 TEST(ImageSurfaceSink, SurfaceSinkWritePixelBlocks)
    582 {
    583  WithSurfaceSink<Orient::NORMAL>(
    584      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
    585        // Create a green buffer the same size as one row of the surface (which
    586        // is 100x100), containing 60 pixels of green in the middle and 20
    587        // transparent pixels on either side.
    588        uint32_t buffer[100];
    589        InitializeRowBuffer(buffer, 100, 20, 80, BGRAColor::Green().AsPixel());
    590 
    591        uint32_t count = 0;
    592        WriteState result = aSink->WritePixelBlocks<uint32_t>(
    593            [&](uint32_t* aBlockStart, int32_t aLength) {
    594              ++count;
    595              EXPECT_EQ(int32_t(100), aLength);
    596              memcpy(aBlockStart, buffer, 100 * sizeof(uint32_t));
    597              return std::make_tuple(int32_t(100), Maybe<WriteState>());
    598            });
    599 
    600        EXPECT_EQ(WriteState::FINISHED, result);
    601        EXPECT_EQ(100u, count);
    602 
    603        AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 100),
    604                                        IntRect(0, 0, 100, 100));
    605 
    606        // Check that the generated image is correct.
    607        CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
    608 
    609        // Attempt to write more and make sure that nothing gets written.
    610        count = 0;
    611        result = aSink->WritePixelBlocks<uint32_t>(
    612            [&](uint32_t* aBlockStart, int32_t aLength) {
    613              count++;
    614              for (int32_t i = 0; i < aLength; ++i) {
    615                aBlockStart[i] = BGRAColor::Red().AsPixel();
    616              }
    617              return std::make_tuple(aLength, Maybe<WriteState>());
    618            });
    619 
    620        EXPECT_EQ(WriteState::FINISHED, result);
    621        EXPECT_EQ(0u, count);
    622        EXPECT_TRUE(aSink->IsSurfaceFinished());
    623 
    624        // Check that the generated image is still correct.
    625        CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
    626      });
    627 }
    628 
    629 TEST(ImageSurfaceSink, SurfaceSinkWritePixelBlocksPartialRow)
    630 {
    631  WithSurfaceSink<Orient::NORMAL>([](image::Decoder* aDecoder,
    632                                     SurfaceSink* aSink) {
    633    // Create a green buffer the same size as one row of the surface (which is
    634    // 100x100), containing 60 pixels of green in the middle and 20 transparent
    635    // pixels on either side.
    636    uint32_t buffer[100];
    637    InitializeRowBuffer(buffer, 100, 20, 80, BGRAColor::Green().AsPixel());
    638 
    639    // Write the first 99 rows of our 100x100 surface and verify that even
    640    // though our lambda will yield pixels forever, only one row is written per
    641    // call to WritePixelsToRow().
    642    for (int row = 0; row < 99; ++row) {
    643      for (int32_t written = 0; written < 100;) {
    644        WriteState result = aSink->WritePixelBlocks<uint32_t>(
    645            [&](uint32_t* aBlockStart, int32_t aLength) {
    646              // When we write the final block of pixels, it will request we
    647              // start another row. We should abort at that point.
    648              if (aLength == int32_t(100) && written == int32_t(100)) {
    649                return std::make_tuple(int32_t(0),
    650                                       Some(WriteState::NEED_MORE_DATA));
    651              }
    652 
    653              // It should always request enough data to fill the row. So it
    654              // should request 100, 75, 50, and finally 25 pixels.
    655              EXPECT_EQ(int32_t(100) - written, aLength);
    656 
    657              // Only write one quarter of the pixels for the row.
    658              memcpy(aBlockStart, &buffer[written], 25 * sizeof(uint32_t));
    659              written += 25;
    660 
    661              // We've written the last pixels remaining for the row.
    662              if (written == int32_t(100)) {
    663                return std::make_tuple(int32_t(25), Maybe<WriteState>());
    664              }
    665 
    666              // We've written another quarter of the row but not yet all of it.
    667              return std::make_tuple(int32_t(25),
    668                                     Some(WriteState::NEED_MORE_DATA));
    669            });
    670 
    671        EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    672      }
    673 
    674      EXPECT_FALSE(aSink->IsSurfaceFinished());
    675 
    676      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    677      EXPECT_TRUE(invalidRect.isSome());
    678      EXPECT_EQ(OrientedIntRect(0, row, 100, 1), invalidRect->mInputSpaceRect);
    679      EXPECT_EQ(OrientedIntRect(0, row, 100, 1), invalidRect->mOutputSpaceRect);
    680 
    681      CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, row + 1));
    682    }
    683 
    684    // Write the final line, which should finish the surface.
    685    uint32_t count = 0;
    686    WriteState result = aSink->WritePixelBlocks<uint32_t>(
    687        [&](uint32_t* aBlockStart, int32_t aLength) {
    688          ++count;
    689          EXPECT_EQ(int32_t(100), aLength);
    690          memcpy(aBlockStart, buffer, 100 * sizeof(uint32_t));
    691          return std::make_tuple(int32_t(100), Maybe<WriteState>());
    692        });
    693 
    694    EXPECT_EQ(WriteState::FINISHED, result);
    695    EXPECT_EQ(1u, count);
    696 
    697    // Note that the final invalid rect we expect here is only the last row;
    698    // that's because we called TakeInvalidRect() repeatedly in the loop above.
    699    AssertCorrectPipelineFinalState(aSink, IntRect(0, 99, 100, 1),
    700                                    IntRect(0, 99, 100, 1));
    701 
    702    // Check that the generated image is correct.
    703    CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
    704 
    705    // Attempt to write more and make sure that nothing gets written.
    706    count = 0;
    707    result = aSink->WritePixelBlocks<uint32_t>(
    708        [&](uint32_t* aBlockStart, int32_t aLength) {
    709          count++;
    710          for (int32_t i = 0; i < aLength; ++i) {
    711            aBlockStart[i] = BGRAColor::Red().AsPixel();
    712          }
    713          return std::make_tuple(aLength, Maybe<WriteState>());
    714        });
    715 
    716    EXPECT_EQ(WriteState::FINISHED, result);
    717    EXPECT_EQ(0u, count);
    718    EXPECT_TRUE(aSink->IsSurfaceFinished());
    719 
    720    // Check that the generated image is still correct.
    721    CheckGeneratedImage(aDecoder, IntRect(20, 0, 60, 100));
    722  });
    723 }
    724 
    725 TEST(ImageSurfaceSink, SurfaceSinkProgressivePasses)
    726 {
    727  WithSurfaceSink<Orient::NORMAL>(
    728      [](image::Decoder* aDecoder, SurfaceSink* aSink) {
    729        {
    730          // Fill the image with a first pass of red.
    731          uint32_t count = 0;
    732          auto result = aSink->WritePixels<uint32_t>([&]() {
    733            ++count;
    734            return AsVariant(BGRAColor::Red().AsPixel());
    735          });
    736          EXPECT_EQ(WriteState::FINISHED, result);
    737          EXPECT_EQ(100u * 100u, count);
    738 
    739          AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 100),
    740                                          IntRect(0, 0, 100, 100));
    741 
    742          // Check that the generated image is correct.
    743          RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    744          RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    745          EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Red()));
    746        }
    747 
    748        {
    749          ResetForNextPass(aSink);
    750 
    751          // Check that the generated image is still the first pass image.
    752          RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    753          RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    754          EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Red()));
    755        }
    756 
    757        {
    758          // Fill the image with a second pass of green.
    759          uint32_t count = 0;
    760          auto result = aSink->WritePixels<uint32_t>([&]() {
    761            ++count;
    762            return AsVariant(BGRAColor::Green().AsPixel());
    763          });
    764          EXPECT_EQ(WriteState::FINISHED, result);
    765          EXPECT_EQ(100u * 100u, count);
    766 
    767          AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 100),
    768                                          IntRect(0, 0, 100, 100));
    769 
    770          // Check that the generated image is correct.
    771          RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    772          RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    773          EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green()));
    774        }
    775      });
    776 }
    777 
    778 TEST(ImageSurfaceSink, SurfaceSinkInvalidRect)
    779 {
    780  WithSurfaceSink<Orient::NORMAL>([](image::Decoder* aDecoder,
    781                                     SurfaceSink* aSink) {
    782    {
    783      // Write one row.
    784      uint32_t count = 0;
    785      auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    786        if (count == 100) {
    787          return AsVariant(WriteState::NEED_MORE_DATA);
    788        }
    789        count++;
    790        return AsVariant(BGRAColor::Green().AsPixel());
    791      });
    792      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    793      EXPECT_EQ(100u, count);
    794      EXPECT_FALSE(aSink->IsSurfaceFinished());
    795 
    796      // Assert that we have the right invalid rect.
    797      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    798      EXPECT_TRUE(invalidRect.isSome());
    799      EXPECT_EQ(OrientedIntRect(0, 0, 100, 1), invalidRect->mInputSpaceRect);
    800      EXPECT_EQ(OrientedIntRect(0, 0, 100, 1), invalidRect->mOutputSpaceRect);
    801    }
    802 
    803    {
    804      // Write eight rows.
    805      uint32_t count = 0;
    806      auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    807        if (count == 100 * 8) {
    808          return AsVariant(WriteState::NEED_MORE_DATA);
    809        }
    810        count++;
    811        return AsVariant(BGRAColor::Green().AsPixel());
    812      });
    813      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    814      EXPECT_EQ(100u * 8u, count);
    815      EXPECT_FALSE(aSink->IsSurfaceFinished());
    816 
    817      // Assert that we have the right invalid rect.
    818      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    819      EXPECT_TRUE(invalidRect.isSome());
    820      EXPECT_EQ(OrientedIntRect(0, 1, 100, 8), invalidRect->mInputSpaceRect);
    821      EXPECT_EQ(OrientedIntRect(0, 1, 100, 8), invalidRect->mOutputSpaceRect);
    822    }
    823 
    824    {
    825      // Write the left half of one row.
    826      uint32_t count = 0;
    827      auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    828        if (count == 50) {
    829          return AsVariant(WriteState::NEED_MORE_DATA);
    830        }
    831        count++;
    832        return AsVariant(BGRAColor::Green().AsPixel());
    833      });
    834      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    835      EXPECT_EQ(50u, count);
    836      EXPECT_FALSE(aSink->IsSurfaceFinished());
    837 
    838      // Assert that we don't have an invalid rect, since the invalid rect only
    839      // gets updated when a row gets completed.
    840      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    841      EXPECT_TRUE(invalidRect.isNothing());
    842    }
    843 
    844    {
    845      // Write the right half of the same row.
    846      uint32_t count = 0;
    847      auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    848        if (count == 50) {
    849          return AsVariant(WriteState::NEED_MORE_DATA);
    850        }
    851        count++;
    852        return AsVariant(BGRAColor::Green().AsPixel());
    853      });
    854      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    855      EXPECT_EQ(50u, count);
    856      EXPECT_FALSE(aSink->IsSurfaceFinished());
    857 
    858      // Assert that we have the right invalid rect, which will include both the
    859      // left and right halves of this row now that we've completed it.
    860      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    861      EXPECT_TRUE(invalidRect.isSome());
    862      EXPECT_EQ(OrientedIntRect(0, 9, 100, 1), invalidRect->mInputSpaceRect);
    863      EXPECT_EQ(OrientedIntRect(0, 9, 100, 1), invalidRect->mOutputSpaceRect);
    864    }
    865 
    866    {
    867      // Write no rows.
    868      auto result = aSink->WritePixels<uint32_t>(
    869          [&]() { return AsVariant(WriteState::NEED_MORE_DATA); });
    870      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    871      EXPECT_FALSE(aSink->IsSurfaceFinished());
    872 
    873      // Assert that we don't have an invalid rect.
    874      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    875      EXPECT_TRUE(invalidRect.isNothing());
    876    }
    877 
    878    {
    879      // Fill the rest of the image.
    880      uint32_t count = 0;
    881      auto result = aSink->WritePixels<uint32_t>([&]() {
    882        count++;
    883        return AsVariant(BGRAColor::Green().AsPixel());
    884      });
    885      EXPECT_EQ(WriteState::FINISHED, result);
    886      EXPECT_EQ(100u * 90u, count);
    887      EXPECT_TRUE(aSink->IsSurfaceFinished());
    888 
    889      // Assert that we have the right invalid rect.
    890      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    891      EXPECT_TRUE(invalidRect.isSome());
    892      EXPECT_EQ(OrientedIntRect(0, 10, 100, 90), invalidRect->mInputSpaceRect);
    893      EXPECT_EQ(OrientedIntRect(0, 10, 100, 90), invalidRect->mOutputSpaceRect);
    894 
    895      // Check that the generated image is correct.
    896      RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    897      RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    898      EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green()));
    899    }
    900  });
    901 }
    902 
    903 TEST(ImageSurfaceSink, SurfaceSinkFlipVertically)
    904 {
    905  WithSurfaceSink<Orient::FLIP_VERTICALLY>([](image::Decoder* aDecoder,
    906                                              SurfaceSink* aSink) {
    907    {
    908      // Fill the image with a first pass of red.
    909      uint32_t count = 0;
    910      auto result = aSink->WritePixels<uint32_t>([&]() {
    911        ++count;
    912        return AsVariant(BGRAColor::Red().AsPixel());
    913      });
    914      EXPECT_EQ(WriteState::FINISHED, result);
    915      EXPECT_EQ(100u * 100u, count);
    916 
    917      AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 100),
    918                                      IntRect(0, 0, 100, 100));
    919 
    920      // Check that the generated image is correct.
    921      RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    922      RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    923      EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Red()));
    924    }
    925 
    926    {
    927      ResetForNextPass(aSink);
    928 
    929      // Check that the generated image is still the first pass image.
    930      RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    931      RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    932      EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Red()));
    933    }
    934 
    935    {
    936      // Fill 25 rows of the image with green and make sure everything is OK.
    937      uint32_t count = 0;
    938      auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    939        if (count == 25 * 100) {
    940          return AsVariant(WriteState::NEED_MORE_DATA);
    941        }
    942        count++;
    943        return AsVariant(BGRAColor::Green().AsPixel());
    944      });
    945      EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
    946      EXPECT_EQ(25u * 100u, count);
    947      EXPECT_FALSE(aSink->IsSurfaceFinished());
    948 
    949      // Assert that we have the right invalid rect, which should include the
    950      // *bottom* (since we're flipping vertically) 25 rows of the image.
    951      Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
    952      EXPECT_TRUE(invalidRect.isSome());
    953      EXPECT_EQ(OrientedIntRect(0, 75, 100, 25), invalidRect->mInputSpaceRect);
    954      EXPECT_EQ(OrientedIntRect(0, 75, 100, 25), invalidRect->mOutputSpaceRect);
    955 
    956      // Check that the generated image is correct.
    957      RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    958      RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    959      EXPECT_TRUE(RowsAreSolidColor(surface, 0, 75, BGRAColor::Red()));
    960      EXPECT_TRUE(RowsAreSolidColor(surface, 75, 25, BGRAColor::Green()));
    961    }
    962 
    963    {
    964      // Fill the rest of the image with a second pass of green.
    965      uint32_t count = 0;
    966      auto result = aSink->WritePixels<uint32_t>([&]() {
    967        ++count;
    968        return AsVariant(BGRAColor::Green().AsPixel());
    969      });
    970      EXPECT_EQ(WriteState::FINISHED, result);
    971      EXPECT_EQ(75u * 100u, count);
    972 
    973      AssertCorrectPipelineFinalState(aSink, IntRect(0, 0, 100, 75),
    974                                      IntRect(0, 0, 100, 75));
    975 
    976      // Check that the generated image is correct.
    977      RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    978      RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    979      EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green()));
    980    }
    981  });
    982 }