tor-browser

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

TestDeinterlacingFilter.cpp (27706B)


      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 "SurfaceFilters.h"
     15 #include "SurfacePipe.h"
     16 
     17 using namespace mozilla;
     18 using namespace mozilla::gfx;
     19 using namespace mozilla::image;
     20 
     21 template <typename Func>
     22 void WithDeinterlacingFilter(const IntSize& aSize, bool aProgressiveDisplay,
     23                             Func aFunc) {
     24  RefPtr<image::Decoder> decoder = CreateTrivialDecoder();
     25  ASSERT_TRUE(bool(decoder));
     26 
     27  WithFilterPipeline(
     28      decoder, std::forward<Func>(aFunc),
     29      DeinterlacingConfig<uint32_t>{aProgressiveDisplay},
     30      SurfaceConfig{decoder, aSize, SurfaceFormat::OS_RGBA, false});
     31 }
     32 
     33 void AssertConfiguringDeinterlacingFilterFails(const IntSize& aSize) {
     34  RefPtr<image::Decoder> decoder = CreateTrivialDecoder();
     35  ASSERT_TRUE(decoder != nullptr);
     36 
     37  AssertConfiguringPipelineFails(
     38      decoder, DeinterlacingConfig<uint32_t>{/* mProgressiveDisplay = */ true},
     39      SurfaceConfig{decoder, aSize, SurfaceFormat::OS_RGBA, false});
     40 }
     41 
     42 class ImageDeinterlacingFilter : public ::testing::Test {
     43 protected:
     44  AutoInitializeImageLib mInit;
     45 };
     46 
     47 TEST_F(ImageDeinterlacingFilter, WritePixels100_100) {
     48  WithDeinterlacingFilter(
     49      IntSize(100, 100), /* aProgressiveDisplay = */ true,
     50      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
     51        CheckWritePixels(aDecoder, aFilter,
     52                         /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
     53                         /* aInputRect = */ Some(IntRect(0, 0, 100, 100)));
     54      });
     55 }
     56 
     57 TEST_F(ImageDeinterlacingFilter, WritePixels99_99) {
     58  WithDeinterlacingFilter(IntSize(99, 99), /* aProgressiveDisplay = */ true,
     59                          [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
     60                            CheckWritePixels(
     61                                aDecoder, aFilter,
     62                                /* aOutputRect = */ Some(IntRect(0, 0, 99, 99)),
     63                                /* aInputRect = */ Some(IntRect(0, 0, 99, 99)));
     64                          });
     65 }
     66 
     67 TEST_F(ImageDeinterlacingFilter, WritePixels8_8) {
     68  WithDeinterlacingFilter(IntSize(8, 8), /* aProgressiveDisplay = */ true,
     69                          [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
     70                            CheckWritePixels(
     71                                aDecoder, aFilter,
     72                                /* aOutputRect = */ Some(IntRect(0, 0, 8, 8)),
     73                                /* aInputRect = */ Some(IntRect(0, 0, 8, 8)));
     74                          });
     75 }
     76 
     77 TEST_F(ImageDeinterlacingFilter, WritePixels7_7) {
     78  WithDeinterlacingFilter(IntSize(7, 7), /* aProgressiveDisplay = */ true,
     79                          [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
     80                            CheckWritePixels(
     81                                aDecoder, aFilter,
     82                                /* aOutputRect = */ Some(IntRect(0, 0, 7, 7)),
     83                                /* aInputRect = */ Some(IntRect(0, 0, 7, 7)));
     84                          });
     85 }
     86 
     87 TEST_F(ImageDeinterlacingFilter, WritePixels3_3) {
     88  WithDeinterlacingFilter(IntSize(3, 3), /* aProgressiveDisplay = */ true,
     89                          [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
     90                            CheckWritePixels(
     91                                aDecoder, aFilter,
     92                                /* aOutputRect = */ Some(IntRect(0, 0, 3, 3)),
     93                                /* aInputRect = */ Some(IntRect(0, 0, 3, 3)));
     94                          });
     95 }
     96 
     97 TEST_F(ImageDeinterlacingFilter, WritePixels1_1) {
     98  WithDeinterlacingFilter(IntSize(1, 1), /* aProgressiveDisplay = */ true,
     99                          [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    100                            CheckWritePixels(
    101                                aDecoder, aFilter,
    102                                /* aOutputRect = */ Some(IntRect(0, 0, 1, 1)),
    103                                /* aInputRect = */ Some(IntRect(0, 0, 1, 1)));
    104                          });
    105 }
    106 
    107 TEST_F(ImageDeinterlacingFilter, WritePixelsNonProgressiveOutput51_52) {
    108  WithDeinterlacingFilter(
    109      IntSize(51, 52), /* aProgressiveDisplay = */ false,
    110      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    111        // Fill the image. The output should be green for even rows and red for
    112        // odd rows but we need to write the rows in the order that the
    113        // deinterlacer expects them.
    114        uint32_t count = 0;
    115        auto result = aFilter->WritePixels<uint32_t>([&]() {
    116          uint32_t row = count / 51;  // Integer division.
    117          ++count;
    118 
    119          // Note that we use a switch statement here, even though it's quite
    120          // verbose, because it's useful to have the mappings between input and
    121          // output rows available when debugging these tests.
    122 
    123          switch (row) {
    124            // First pass. Output rows are positioned at 8n + 0.
    125            case 0:  // Output row 0.
    126            case 1:  // Output row 8.
    127            case 2:  // Output row 16.
    128            case 3:  // Output row 24.
    129            case 4:  // Output row 32.
    130            case 5:  // Output row 40.
    131            case 6:  // Output row 48.
    132              return AsVariant(BGRAColor::Green().AsPixel());
    133 
    134            // Second pass. Rows are positioned at 8n + 4.
    135            case 7:   // Output row 4.
    136            case 8:   // Output row 12.
    137            case 9:   // Output row 20.
    138            case 10:  // Output row 28.
    139            case 11:  // Output row 36.
    140            case 12:  // Output row 44.
    141              return AsVariant(BGRAColor::Green().AsPixel());
    142 
    143            // Third pass. Rows are positioned at 4n + 2.
    144            case 13:  // Output row 2.
    145            case 14:  // Output row 6.
    146            case 15:  // Output row 10.
    147            case 16:  // Output row 14.
    148            case 17:  // Output row 18.
    149            case 18:  // Output row 22.
    150            case 19:  // Output row 26.
    151            case 20:  // Output row 30.
    152            case 21:  // Output row 34.
    153            case 22:  // Output row 38.
    154            case 23:  // Output row 42.
    155            case 24:  // Output row 46.
    156            case 25:  // Output row 50.
    157              return AsVariant(BGRAColor::Green().AsPixel());
    158 
    159            // Fourth pass. Rows are positioned at 2n + 1.
    160            case 26:  // Output row 1.
    161            case 27:  // Output row 3.
    162            case 28:  // Output row 5.
    163            case 29:  // Output row 7.
    164            case 30:  // Output row 9.
    165            case 31:  // Output row 11.
    166            case 32:  // Output row 13.
    167            case 33:  // Output row 15.
    168            case 34:  // Output row 17.
    169            case 35:  // Output row 19.
    170            case 36:  // Output row 21.
    171            case 37:  // Output row 23.
    172            case 38:  // Output row 25.
    173            case 39:  // Output row 27.
    174            case 40:  // Output row 29.
    175            case 41:  // Output row 31.
    176            case 42:  // Output row 33.
    177            case 43:  // Output row 35.
    178            case 44:  // Output row 37.
    179            case 45:  // Output row 39.
    180            case 46:  // Output row 41.
    181            case 47:  // Output row 43.
    182            case 48:  // Output row 45.
    183            case 49:  // Output row 47.
    184            case 50:  // Output row 49.
    185            case 51:  // Output row 51.
    186              return AsVariant(BGRAColor::Red().AsPixel());
    187 
    188            default:
    189              MOZ_CRASH("Unexpected row");
    190          }
    191        });
    192        EXPECT_EQ(WriteState::FINISHED, result);
    193        EXPECT_EQ(51u * 52u, count);
    194 
    195        AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 51, 52),
    196                                        IntRect(0, 0, 51, 52));
    197 
    198        // Check that the generated image is correct. As mentioned above, we
    199        // expect even rows to be green and odd rows to be red.
    200        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    201        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    202 
    203        for (uint32_t row = 0; row < 52; ++row) {
    204          EXPECT_TRUE(RowsAreSolidColor(
    205              surface, row, 1,
    206              row % 2 == 0 ? BGRAColor::Green() : BGRAColor::Red()));
    207        }
    208      });
    209 }
    210 
    211 TEST_F(ImageDeinterlacingFilter, WritePixelsOutput20_20) {
    212  WithDeinterlacingFilter(
    213      IntSize(20, 20), /* aProgressiveDisplay = */ true,
    214      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    215        // Fill the image. The output should be green for even rows and red for
    216        // odd rows but we need to write the rows in the order that the
    217        // deinterlacer expects them.
    218        uint32_t count = 0;
    219        auto result = aFilter->WritePixels<uint32_t>([&]() {
    220          uint32_t row = count / 20;  // Integer division.
    221          ++count;
    222 
    223          // Note that we use a switch statement here, even though it's quite
    224          // verbose, because it's useful to have the mappings between input and
    225          // output rows available when debugging these tests.
    226 
    227          switch (row) {
    228            // First pass. Output rows are positioned at 8n + 0.
    229            case 0:  // Output row 0.
    230            case 1:  // Output row 8.
    231            case 2:  // Output row 16.
    232              return AsVariant(BGRAColor::Green().AsPixel());
    233 
    234            // Second pass. Rows are positioned at 8n + 4.
    235            case 3:  // Output row 4.
    236            case 4:  // Output row 12.
    237              return AsVariant(BGRAColor::Green().AsPixel());
    238 
    239            // Third pass. Rows are positioned at 4n + 2.
    240            case 5:  // Output row 2.
    241            case 6:  // Output row 6.
    242            case 7:  // Output row 10.
    243            case 8:  // Output row 14.
    244            case 9:  // Output row 18.
    245              return AsVariant(BGRAColor::Green().AsPixel());
    246 
    247            // Fourth pass. Rows are positioned at 2n + 1.
    248            case 10:  // Output row 1.
    249            case 11:  // Output row 3.
    250            case 12:  // Output row 5.
    251            case 13:  // Output row 7.
    252            case 14:  // Output row 9.
    253            case 15:  // Output row 11.
    254            case 16:  // Output row 13.
    255            case 17:  // Output row 15.
    256            case 18:  // Output row 17.
    257            case 19:  // Output row 19.
    258              return AsVariant(BGRAColor::Red().AsPixel());
    259 
    260            default:
    261              MOZ_CRASH("Unexpected row");
    262          }
    263        });
    264        EXPECT_EQ(WriteState::FINISHED, result);
    265        EXPECT_EQ(20u * 20u, count);
    266 
    267        AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 20, 20),
    268                                        IntRect(0, 0, 20, 20));
    269 
    270        // Check that the generated image is correct. As mentioned above, we
    271        // expect even rows to be green and odd rows to be red.
    272        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    273        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    274 
    275        for (uint32_t row = 0; row < 20; ++row) {
    276          EXPECT_TRUE(RowsAreSolidColor(
    277              surface, row, 1,
    278              row % 2 == 0 ? BGRAColor::Green() : BGRAColor::Red()));
    279        }
    280      });
    281 }
    282 
    283 TEST_F(ImageDeinterlacingFilter, WritePixelsOutput7_7) {
    284  WithDeinterlacingFilter(
    285      IntSize(7, 7), /* aProgressiveDisplay = */ true,
    286      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    287        // Fill the image. The output should be a repeating pattern of two green
    288        // rows followed by two red rows but we need to write the rows in the
    289        // order that the deinterlacer expects them.
    290        uint32_t count = 0;
    291        auto result = aFilter->WritePixels<uint32_t>([&]() {
    292          uint32_t row = count / 7;  // Integer division.
    293          ++count;
    294 
    295          switch (row) {
    296            // First pass. Output rows are positioned at 8n + 0.
    297            case 0:  // Output row 0.
    298              return AsVariant(BGRAColor::Green().AsPixel());
    299 
    300            // Second pass. Rows are positioned at 8n + 4.
    301            case 1:  // Output row 4.
    302              return AsVariant(BGRAColor::Green().AsPixel());
    303 
    304            // Third pass. Rows are positioned at 4n + 2.
    305            case 2:  // Output row 2.
    306            case 3:  // Output row 6.
    307              return AsVariant(BGRAColor::Red().AsPixel());
    308 
    309            // Fourth pass. Rows are positioned at 2n + 1.
    310            case 4:  // Output row 1.
    311              return AsVariant(BGRAColor::Green().AsPixel());
    312 
    313            case 5:  // Output row 3.
    314              return AsVariant(BGRAColor::Red().AsPixel());
    315 
    316            case 6:  // Output row 5.
    317              return AsVariant(BGRAColor::Green().AsPixel());
    318 
    319            default:
    320              MOZ_CRASH("Unexpected row");
    321          }
    322        });
    323        EXPECT_EQ(WriteState::FINISHED, result);
    324        EXPECT_EQ(7u * 7u, count);
    325 
    326        AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 7, 7),
    327                                        IntRect(0, 0, 7, 7));
    328 
    329        // Check that the generated image is correct. As mentioned above, we
    330        // expect two green rows, followed by two red rows, then two green rows,
    331        // etc.
    332        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    333        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    334 
    335        for (uint32_t row = 0; row < 7; ++row) {
    336          BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
    337                                ? BGRAColor::Green()
    338                                : BGRAColor::Red();
    339          EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
    340        }
    341      });
    342 }
    343 
    344 TEST_F(ImageDeinterlacingFilter, WritePixelsOutput3_3) {
    345  WithDeinterlacingFilter(
    346      IntSize(3, 3), /* aProgressiveDisplay = */ true,
    347      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    348        // Fill the image. The output should be green, red, green in that order,
    349        // but we need to write the rows in the order that the deinterlacer
    350        // expects them.
    351        uint32_t count = 0;
    352        auto result = aFilter->WritePixels<uint32_t>([&]() {
    353          uint32_t row = count / 3;  // Integer division.
    354          ++count;
    355 
    356          switch (row) {
    357            // First pass. Output rows are positioned at 8n + 0.
    358            case 0:  // Output row 0.
    359              return AsVariant(BGRAColor::Green().AsPixel());
    360 
    361            // Second pass. Rows are positioned at 8n + 4.
    362            // No rows for this pass.
    363 
    364            // Third pass. Rows are positioned at 4n + 2.
    365            case 1:  // Output row 2.
    366              return AsVariant(BGRAColor::Green().AsPixel());
    367 
    368            // Fourth pass. Rows are positioned at 2n + 1.
    369            case 2:  // Output row 1.
    370              return AsVariant(BGRAColor::Red().AsPixel());
    371 
    372            default:
    373              MOZ_CRASH("Unexpected row");
    374          }
    375        });
    376        EXPECT_EQ(WriteState::FINISHED, result);
    377        EXPECT_EQ(3u * 3u, count);
    378 
    379        AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 3, 3),
    380                                        IntRect(0, 0, 3, 3));
    381 
    382        // Check that the generated image is correct. As mentioned above, we
    383        // expect green, red, green in that order.
    384        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    385        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    386 
    387        for (uint32_t row = 0; row < 3; ++row) {
    388          EXPECT_TRUE(RowsAreSolidColor(
    389              surface, row, 1,
    390              row == 0 || row == 2 ? BGRAColor::Green() : BGRAColor::Red()));
    391        }
    392      });
    393 }
    394 
    395 TEST_F(ImageDeinterlacingFilter, WritePixelsOutput1_1) {
    396  WithDeinterlacingFilter(
    397      IntSize(1, 1), /* aProgressiveDisplay = */ true,
    398      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    399        // Fill the image. The output should be a single red row.
    400        uint32_t count = 0;
    401        auto result = aFilter->WritePixels<uint32_t>([&]() {
    402          ++count;
    403          return AsVariant(BGRAColor::Red().AsPixel());
    404        });
    405        EXPECT_EQ(WriteState::FINISHED, result);
    406        EXPECT_EQ(1u, count);
    407 
    408        AssertCorrectPipelineFinalState(aFilter, IntRect(0, 0, 1, 1),
    409                                        IntRect(0, 0, 1, 1));
    410 
    411        // Check that the generated image is correct. As mentioned above, we
    412        // expect a single red row.
    413        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    414        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    415 
    416        EXPECT_TRUE(RowsAreSolidColor(surface, 0, 1, BGRAColor::Red()));
    417      });
    418 }
    419 
    420 void WriteRowAndCheckInterlacerOutput(image::Decoder* aDecoder,
    421                                      SurfaceFilter* aFilter, BGRAColor aColor,
    422                                      WriteState aNextState,
    423                                      OrientedIntRect aInvalidRect,
    424                                      uint32_t aFirstHaeberliRow,
    425                                      uint32_t aLastHaeberliRow) {
    426  uint32_t count = 0;
    427 
    428  auto result = aFilter->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
    429    if (count < 7) {
    430      ++count;
    431      return AsVariant(aColor.AsPixel());
    432    }
    433    return AsVariant(WriteState::NEED_MORE_DATA);
    434  });
    435 
    436  EXPECT_EQ(aNextState, result);
    437  EXPECT_EQ(7u, count);
    438 
    439  // Assert that we got the expected invalidation region.
    440  Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
    441  EXPECT_TRUE(invalidRect.isSome());
    442  EXPECT_EQ(aInvalidRect, invalidRect->mInputSpaceRect);
    443  EXPECT_EQ(aInvalidRect, invalidRect->mOutputSpaceRect);
    444 
    445  // Check that the portion of the image generated so far is correct. The rows
    446  // from aFirstHaeberliRow to aLastHaeberliRow should be filled with aColor.
    447  // Note that this is not the same as the set of rows in aInvalidRect, because
    448  // after writing a row the deinterlacer seeks to the next row to write, which
    449  // may involve copying previously-written rows in the buffer to the output
    450  // even though they don't change in this pass.
    451  RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    452  RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    453 
    454  for (uint32_t row = aFirstHaeberliRow; row <= aLastHaeberliRow; ++row) {
    455    EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, aColor));
    456  }
    457 }
    458 
    459 TEST_F(ImageDeinterlacingFilter, WritePixelsIntermediateOutput7_7) {
    460  WithDeinterlacingFilter(
    461      IntSize(7, 7), /* aProgressiveDisplay = */ true,
    462      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    463        // Fill the image. The output should be a repeating pattern of two green
    464        // rows followed by two red rows but we need to write the rows in the
    465        // order that the deinterlacer expects them.
    466 
    467        // First pass. Output rows are positioned at 8n + 0.
    468 
    469        // Output row 0. The invalid rect is the entire image because this is
    470        // the end of the first pass.
    471        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
    472                                         WriteState::NEED_MORE_DATA,
    473                                         OrientedIntRect(0, 0, 7, 7), 0, 4);
    474 
    475        // Second pass. Rows are positioned at 8n + 4.
    476 
    477        // Output row 4. The invalid rect is the entire image because this is
    478        // the end of the second pass.
    479        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
    480                                         WriteState::NEED_MORE_DATA,
    481                                         OrientedIntRect(0, 0, 7, 7), 1, 4);
    482 
    483        // Third pass. Rows are positioned at 4n + 2.
    484 
    485        // Output row 2. The invalid rect contains the Haeberli rows for this
    486        // output row (rows 2 and 3) as well as the rows that we copy from
    487        // previous passes when seeking to the next output row (rows 4 and 5).
    488        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
    489                                         WriteState::NEED_MORE_DATA,
    490                                         OrientedIntRect(0, 2, 7, 4), 2, 3);
    491 
    492        // Output row 6. The invalid rect is the entire image because this is
    493        // the end of the third pass.
    494        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
    495                                         WriteState::NEED_MORE_DATA,
    496                                         OrientedIntRect(0, 0, 7, 7), 6, 6);
    497 
    498        // Fourth pass. Rows are positioned at 2n + 1.
    499 
    500        // Output row 1. The invalid rect contains the Haeberli rows for this
    501        // output row (just row 1) as well as the rows that we copy from
    502        // previous passes when seeking to the next output row (row 2).
    503        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
    504                                         WriteState::NEED_MORE_DATA,
    505                                         OrientedIntRect(0, 1, 7, 2), 1, 1);
    506 
    507        // Output row 3. The invalid rect contains the Haeberli rows for this
    508        // output row (just row 3) as well as the rows that we copy from
    509        // previous passes when seeking to the next output row (row 4).
    510        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
    511                                         WriteState::NEED_MORE_DATA,
    512                                         OrientedIntRect(0, 3, 7, 2), 3, 3);
    513 
    514        // Output row 5. The invalid rect contains the Haeberli rows for this
    515        // output row (just row 5) as well as the rows that we copy from
    516        // previous passes when seeking to the next output row (row 6).
    517        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
    518                                         WriteState::FINISHED,
    519                                         OrientedIntRect(0, 5, 7, 2), 5, 5);
    520 
    521        // Assert that we're in the expected final state.
    522        EXPECT_TRUE(aFilter->IsSurfaceFinished());
    523        Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
    524        EXPECT_TRUE(invalidRect.isNothing());
    525 
    526        // Check that the generated image is correct. As mentioned above, we
    527        // expect two green rows, followed by two red rows, then two green rows,
    528        // etc.
    529        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    530        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    531 
    532        for (uint32_t row = 0; row < 7; ++row) {
    533          BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
    534                                ? BGRAColor::Green()
    535                                : BGRAColor::Red();
    536          EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
    537        }
    538      });
    539 }
    540 
    541 TEST_F(ImageDeinterlacingFilter,
    542       WritePixelsNonProgressiveIntermediateOutput7_7) {
    543  WithDeinterlacingFilter(
    544      IntSize(7, 7), /* aProgressiveDisplay = */ false,
    545      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    546        // Fill the image. The output should be a repeating pattern of two green
    547        // rows followed by two red rows but we need to write the rows in the
    548        // order that the deinterlacer expects them.
    549 
    550        // First pass. Output rows are positioned at 8n + 0.
    551 
    552        // Output row 0. The invalid rect is the entire image because this is
    553        // the end of the first pass.
    554        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
    555                                         WriteState::NEED_MORE_DATA,
    556                                         OrientedIntRect(0, 0, 7, 7), 0, 0);
    557 
    558        // Second pass. Rows are positioned at 8n + 4.
    559 
    560        // Output row 4. The invalid rect is the entire image because this is
    561        // the end of the second pass.
    562        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
    563                                         WriteState::NEED_MORE_DATA,
    564                                         OrientedIntRect(0, 0, 7, 7), 4, 4);
    565 
    566        // Third pass. Rows are positioned at 4n + 2.
    567 
    568        // Output row 2. The invalid rect contains the Haeberli rows for this
    569        // output row (rows 2 and 3) as well as the rows that we copy from
    570        // previous passes when seeking to the next output row (rows 4 and 5).
    571        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
    572                                         WriteState::NEED_MORE_DATA,
    573                                         OrientedIntRect(0, 2, 7, 4), 2, 2);
    574 
    575        // Output row 6. The invalid rect is the entire image because this is
    576        // the end of the third pass.
    577        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
    578                                         WriteState::NEED_MORE_DATA,
    579                                         OrientedIntRect(0, 0, 7, 7), 6, 6);
    580 
    581        // Fourth pass. Rows are positioned at 2n + 1.
    582 
    583        // Output row 1. The invalid rect contains the Haeberli rows for this
    584        // output row (just row 1) as well as the rows that we copy from
    585        // previous passes when seeking to the next output row (row 2).
    586        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
    587                                         WriteState::NEED_MORE_DATA,
    588                                         OrientedIntRect(0, 1, 7, 2), 1, 1);
    589 
    590        // Output row 3. The invalid rect contains the Haeberli rows for this
    591        // output row (just row 3) as well as the rows that we copy from
    592        // previous passes when seeking to the next output row (row 4).
    593        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
    594                                         WriteState::NEED_MORE_DATA,
    595                                         OrientedIntRect(0, 3, 7, 2), 3, 3);
    596 
    597        // Output row 5. The invalid rect contains the Haeberli rows for this
    598        // output row (just row 5) as well as the rows that we copy from
    599        // previous passes when seeking to the next output row (row 6).
    600        WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
    601                                         WriteState::FINISHED,
    602                                         OrientedIntRect(0, 5, 7, 2), 5, 5);
    603 
    604        // Assert that we're in the expected final state.
    605        EXPECT_TRUE(aFilter->IsSurfaceFinished());
    606        Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
    607        EXPECT_TRUE(invalidRect.isNothing());
    608 
    609        // Check that the generated image is correct. As mentioned above, we
    610        // expect two green rows, followed by two red rows, then two green rows,
    611        // etc.
    612        RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
    613        RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
    614 
    615        for (uint32_t row = 0; row < 7; ++row) {
    616          BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
    617                                ? BGRAColor::Green()
    618                                : BGRAColor::Red();
    619          EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
    620        }
    621      });
    622 }
    623 
    624 TEST_F(ImageDeinterlacingFilter, DeinterlacingFailsFor0_0) {
    625  // A 0x0 input size is invalid, so configuration should fail.
    626  AssertConfiguringDeinterlacingFilterFails(IntSize(0, 0));
    627 }
    628 
    629 TEST_F(ImageDeinterlacingFilter, DeinterlacingFailsForMinus1_Minus1) {
    630  // A negative input size is invalid, so configuration should fail.
    631  AssertConfiguringDeinterlacingFilterFails(IntSize(-1, -1));
    632 }