tor-browser

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

TestBlendAnimationFilter.cpp (19266B)


      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 "skia/src/core/SkColorPriv.h"  // for SkPMSrcOver
     11 #include "Common.h"
     12 #include "Decoder.h"
     13 #include "DecoderFactory.h"
     14 #include "SourceBuffer.h"
     15 #include "SurfaceFilters.h"
     16 #include "SurfacePipe.h"
     17 
     18 using namespace mozilla;
     19 using namespace mozilla::gfx;
     20 using namespace mozilla::image;
     21 
     22 static already_AddRefed<image::Decoder> CreateTrivialBlendingDecoder() {
     23  DecoderType decoderType = DecoderFactory::GetDecoderType("image/gif");
     24  DecoderFlags decoderFlags = DefaultDecoderFlags();
     25  SurfaceFlags surfaceFlags = DefaultSurfaceFlags();
     26  auto sourceBuffer = MakeNotNull<RefPtr<SourceBuffer>>();
     27  return DecoderFactory::CreateAnonymousDecoder(
     28      decoderType, sourceBuffer, Nothing(), decoderFlags, surfaceFlags);
     29 }
     30 
     31 template <typename Func>
     32 RawAccessFrameRef WithBlendAnimationFilter(image::Decoder* aDecoder,
     33                                           const AnimationParams& aAnimParams,
     34                                           const IntSize& aOutputSize,
     35                                           Func aFunc) {
     36  DecoderTestHelper decoderHelper(aDecoder);
     37 
     38  if (!aDecoder->HasAnimation()) {
     39    decoderHelper.PostIsAnimated(aAnimParams.mTimeout);
     40  }
     41 
     42  BlendAnimationConfig blendAnim{aDecoder};
     43  SurfaceConfig surfaceSink{aDecoder, aOutputSize, SurfaceFormat::OS_RGBA,
     44                            false, Some(aAnimParams)};
     45 
     46  auto func = [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
     47    aFunc(aDecoder, aFilter);
     48  };
     49 
     50  WithFilterPipeline(aDecoder, func, false, blendAnim, surfaceSink);
     51 
     52  RawAccessFrameRef current = aDecoder->GetCurrentFrameRef();
     53  if (current) {
     54    decoderHelper.PostFrameStop(Opacity::SOME_TRANSPARENCY);
     55  }
     56 
     57  return current;
     58 }
     59 
     60 void AssertConfiguringBlendAnimationFilterFails(const IntRect& aFrameRect,
     61                                                const IntSize& aOutputSize) {
     62  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
     63  ASSERT_TRUE(decoder != nullptr);
     64 
     65  AnimationParams animParams{aFrameRect, FrameTimeout::FromRawMilliseconds(0),
     66                             0, BlendMethod::SOURCE, DisposalMethod::KEEP};
     67  BlendAnimationConfig blendAnim{decoder};
     68  SurfaceConfig surfaceSink{decoder, aOutputSize, SurfaceFormat::OS_RGBA, false,
     69                            Some(animParams)};
     70  AssertConfiguringPipelineFails(decoder, blendAnim, surfaceSink);
     71 }
     72 
     73 TEST(ImageBlendAnimationFilter, BlendFailsForNegativeFrameRect)
     74 {
     75  // A negative frame rect size is disallowed.
     76  AssertConfiguringBlendAnimationFilterFails(
     77      IntRect(IntPoint(0, 0), IntSize(-1, -1)), IntSize(100, 100));
     78 }
     79 
     80 TEST(ImageBlendAnimationFilter, WriteFullFirstFrame)
     81 {
     82  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
     83  ASSERT_TRUE(decoder != nullptr);
     84 
     85  AnimationParams params{
     86      IntRect(0, 0, 100, 100), FrameTimeout::FromRawMilliseconds(0),
     87      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
     88  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
     89      decoder, params, IntSize(100, 100),
     90      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
     91        CheckWritePixels(aDecoder, aFilter, Some(IntRect(0, 0, 100, 100)));
     92      });
     93  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
     94 }
     95 
     96 TEST(ImageBlendAnimationFilter, WritePartialFirstFrame)
     97 {
     98  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
     99  ASSERT_TRUE(decoder != nullptr);
    100 
    101  AnimationParams params{
    102      IntRect(25, 50, 50, 25), FrameTimeout::FromRawMilliseconds(0),
    103      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
    104  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
    105      decoder, params, IntSize(100, 100),
    106      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    107        CheckWritePixels(aDecoder, aFilter, Some(IntRect(0, 0, 100, 100)),
    108                         Nothing(), Some(IntRect(25, 50, 50, 25)),
    109                         Some(IntRect(25, 50, 50, 25)));
    110      });
    111  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
    112 }
    113 
    114 static void TestWithBlendAnimationFilterClear(BlendMethod aBlendMethod) {
    115  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
    116  ASSERT_TRUE(decoder != nullptr);
    117 
    118  AnimationParams params0{
    119      IntRect(0, 0, 100, 100), FrameTimeout::FromRawMilliseconds(0),
    120      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
    121  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
    122      decoder, params0, IntSize(100, 100),
    123      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    124        auto result = aFilter->WritePixels<uint32_t>(
    125            [&] { return AsVariant(BGRAColor::Green().AsPixel()); });
    126        EXPECT_EQ(WriteState::FINISHED, result);
    127      });
    128  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
    129 
    130  AnimationParams params1{
    131      IntRect(0, 40, 100, 20), FrameTimeout::FromRawMilliseconds(0),
    132      /* aFrameNum */ 1, BlendMethod::SOURCE, DisposalMethod::CLEAR};
    133  RawAccessFrameRef frame1 = WithBlendAnimationFilter(
    134      decoder, params1, IntSize(100, 100),
    135      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    136        auto result = aFilter->WritePixels<uint32_t>(
    137            [&] { return AsVariant(BGRAColor::Red().AsPixel()); });
    138        EXPECT_EQ(WriteState::FINISHED, result);
    139      });
    140  EXPECT_EQ(IntRect(0, 40, 100, 20), frame1->GetDirtyRect());
    141 
    142  ASSERT_TRUE(frame1.get() != nullptr);
    143 
    144  RefPtr<SourceSurface> surface = frame1->GetSourceSurface();
    145  EXPECT_TRUE(RowsAreSolidColor(surface, 0, 40, BGRAColor::Green()));
    146  EXPECT_TRUE(RowsAreSolidColor(surface, 40, 20, BGRAColor::Red()));
    147  EXPECT_TRUE(RowsAreSolidColor(surface, 60, 40, BGRAColor::Green()));
    148 
    149  AnimationParams params2{
    150      IntRect(0, 50, 100, 20), FrameTimeout::FromRawMilliseconds(0),
    151      /* aFrameNum */ 2, aBlendMethod, DisposalMethod::KEEP};
    152  RawAccessFrameRef frame2 = WithBlendAnimationFilter(
    153      decoder, params2, IntSize(100, 100),
    154      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    155        auto result = aFilter->WritePixels<uint32_t>(
    156            [&] { return AsVariant(BGRAColor::Blue().AsPixel()); });
    157        EXPECT_EQ(WriteState::FINISHED, result);
    158      });
    159 
    160  ASSERT_TRUE(frame2.get() != nullptr);
    161 
    162  surface = frame2->GetSourceSurface();
    163  EXPECT_TRUE(RowsAreSolidColor(surface, 0, 40, BGRAColor::Green()));
    164  EXPECT_TRUE(RowsAreSolidColor(surface, 40, 10, BGRAColor::Transparent()));
    165  EXPECT_TRUE(RowsAreSolidColor(surface, 50, 20, BGRAColor::Blue()));
    166  EXPECT_TRUE(RowsAreSolidColor(surface, 70, 30, BGRAColor::Green()));
    167 }
    168 
    169 TEST(ImageBlendAnimationFilter, ClearWithOver)
    170 {
    171  TestWithBlendAnimationFilterClear(BlendMethod::OVER);
    172 }
    173 
    174 TEST(ImageBlendAnimationFilter, ClearWithSource)
    175 {
    176  TestWithBlendAnimationFilterClear(BlendMethod::SOURCE);
    177 }
    178 
    179 TEST(ImageBlendAnimationFilter, KeepWithSource)
    180 {
    181  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
    182  ASSERT_TRUE(decoder != nullptr);
    183 
    184  AnimationParams params0{
    185      IntRect(0, 0, 100, 100), FrameTimeout::FromRawMilliseconds(0),
    186      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
    187  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
    188      decoder, params0, IntSize(100, 100),
    189      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    190        auto result = aFilter->WritePixels<uint32_t>(
    191            [&] { return AsVariant(BGRAColor::Green().AsPixel()); });
    192        EXPECT_EQ(WriteState::FINISHED, result);
    193      });
    194  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
    195 
    196  AnimationParams params1{
    197      IntRect(0, 40, 100, 20), FrameTimeout::FromRawMilliseconds(0),
    198      /* aFrameNum */ 1, BlendMethod::SOURCE, DisposalMethod::KEEP};
    199  RawAccessFrameRef frame1 = WithBlendAnimationFilter(
    200      decoder, params1, IntSize(100, 100),
    201      [](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    202        auto result = aFilter->WritePixels<uint32_t>(
    203            [&] { return AsVariant(BGRAColor::Red().AsPixel()); });
    204        EXPECT_EQ(WriteState::FINISHED, result);
    205      });
    206  EXPECT_EQ(IntRect(0, 40, 100, 20), frame1->GetDirtyRect());
    207 
    208  ASSERT_TRUE(frame1.get() != nullptr);
    209 
    210  RefPtr<SourceSurface> surface = frame1->GetSourceSurface();
    211  EXPECT_TRUE(RowsAreSolidColor(surface, 0, 40, BGRAColor::Green()));
    212  EXPECT_TRUE(RowsAreSolidColor(surface, 40, 20, BGRAColor::Red()));
    213  EXPECT_TRUE(RowsAreSolidColor(surface, 60, 40, BGRAColor::Green()));
    214 }
    215 
    216 TEST(ImageBlendAnimationFilter, KeepWithOver)
    217 {
    218  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
    219  ASSERT_TRUE(decoder != nullptr);
    220 
    221  AnimationParams params0{
    222      IntRect(0, 0, 100, 100), FrameTimeout::FromRawMilliseconds(0),
    223      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
    224  BGRAColor frameColor0(0, 0xFF, 0, 0x40);
    225  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
    226      decoder, params0, IntSize(100, 100),
    227      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    228        auto result = aFilter->WritePixels<uint32_t>(
    229            [&] { return AsVariant(frameColor0.AsPixel()); });
    230        EXPECT_EQ(WriteState::FINISHED, result);
    231      });
    232  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
    233 
    234  AnimationParams params1{
    235      IntRect(0, 40, 100, 20), FrameTimeout::FromRawMilliseconds(0),
    236      /* aFrameNum */ 1, BlendMethod::OVER, DisposalMethod::KEEP};
    237  BGRAColor frameColor1(0, 0, 0xFF, 0x80);
    238  RawAccessFrameRef frame1 = WithBlendAnimationFilter(
    239      decoder, params1, IntSize(100, 100),
    240      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    241        auto result = aFilter->WritePixels<uint32_t>(
    242            [&] { return AsVariant(frameColor1.AsPixel()); });
    243        EXPECT_EQ(WriteState::FINISHED, result);
    244      });
    245  EXPECT_EQ(IntRect(0, 40, 100, 20), frame1->GetDirtyRect());
    246 
    247  ASSERT_TRUE(frame1.get() != nullptr);
    248 
    249  BGRAColor blendedColor(0, 0x20, 0x80, 0xA0, true);  // already premultiplied
    250  EXPECT_EQ(SkPMSrcOver(frameColor1.AsPixel(), frameColor0.AsPixel()),
    251            blendedColor.AsPixel());
    252 
    253  RefPtr<SourceSurface> surface = frame1->GetSourceSurface();
    254  EXPECT_TRUE(RowsAreSolidColor(surface, 0, 40, frameColor0));
    255  EXPECT_TRUE(RowsAreSolidColor(surface, 40, 20, blendedColor));
    256  EXPECT_TRUE(RowsAreSolidColor(surface, 60, 40, frameColor0));
    257 }
    258 
    259 TEST(ImageBlendAnimationFilter, RestorePreviousWithOver)
    260 {
    261  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
    262  ASSERT_TRUE(decoder != nullptr);
    263 
    264  AnimationParams params0{
    265      IntRect(0, 0, 100, 100), FrameTimeout::FromRawMilliseconds(0),
    266      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
    267  BGRAColor frameColor0(0, 0xFF, 0, 0x40);
    268  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
    269      decoder, params0, IntSize(100, 100),
    270      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    271        auto result = aFilter->WritePixels<uint32_t>(
    272            [&] { return AsVariant(frameColor0.AsPixel()); });
    273        EXPECT_EQ(WriteState::FINISHED, result);
    274      });
    275  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
    276 
    277  AnimationParams params1{
    278      IntRect(0, 10, 100, 80), FrameTimeout::FromRawMilliseconds(0),
    279      /* aFrameNum */ 1, BlendMethod::SOURCE, DisposalMethod::RESTORE_PREVIOUS};
    280  BGRAColor frameColor1 = BGRAColor::Green();
    281  RawAccessFrameRef frame1 = WithBlendAnimationFilter(
    282      decoder, params1, IntSize(100, 100),
    283      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    284        auto result = aFilter->WritePixels<uint32_t>(
    285            [&] { return AsVariant(frameColor1.AsPixel()); });
    286        EXPECT_EQ(WriteState::FINISHED, result);
    287      });
    288  EXPECT_EQ(IntRect(0, 10, 100, 80), frame1->GetDirtyRect());
    289 
    290  AnimationParams params2{
    291      IntRect(0, 40, 100, 20), FrameTimeout::FromRawMilliseconds(0),
    292      /* aFrameNum */ 2, BlendMethod::OVER, DisposalMethod::KEEP};
    293  BGRAColor frameColor2(0, 0, 0xFF, 0x80);
    294  RawAccessFrameRef frame2 = WithBlendAnimationFilter(
    295      decoder, params2, IntSize(100, 100),
    296      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    297        auto result = aFilter->WritePixels<uint32_t>(
    298            [&] { return AsVariant(frameColor2.AsPixel()); });
    299        EXPECT_EQ(WriteState::FINISHED, result);
    300      });
    301  EXPECT_EQ(IntRect(0, 10, 100, 80), frame2->GetDirtyRect());
    302 
    303  ASSERT_TRUE(frame2.get() != nullptr);
    304 
    305  BGRAColor blendedColor(0, 0x20, 0x80, 0xA0, true);  // already premultiplied
    306  EXPECT_EQ(SkPMSrcOver(frameColor2.AsPixel(), frameColor0.AsPixel()),
    307            blendedColor.AsPixel());
    308 
    309  RefPtr<SourceSurface> surface = frame2->GetSourceSurface();
    310  EXPECT_TRUE(RowsAreSolidColor(surface, 0, 40, frameColor0));
    311  EXPECT_TRUE(RowsAreSolidColor(surface, 40, 20, blendedColor));
    312  EXPECT_TRUE(RowsAreSolidColor(surface, 60, 40, frameColor0));
    313 }
    314 
    315 TEST(ImageBlendAnimationFilter, RestorePreviousWithSource)
    316 {
    317  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
    318  ASSERT_TRUE(decoder != nullptr);
    319 
    320  AnimationParams params0{
    321      IntRect(0, 0, 100, 100), FrameTimeout::FromRawMilliseconds(0),
    322      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
    323  BGRAColor frameColor0(0, 0xFF, 0, 0x40);
    324  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
    325      decoder, params0, IntSize(100, 100),
    326      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    327        auto result = aFilter->WritePixels<uint32_t>(
    328            [&] { return AsVariant(frameColor0.AsPixel()); });
    329        EXPECT_EQ(WriteState::FINISHED, result);
    330      });
    331  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
    332 
    333  AnimationParams params1{
    334      IntRect(0, 10, 100, 80), FrameTimeout::FromRawMilliseconds(0),
    335      /* aFrameNum */ 1, BlendMethod::SOURCE, DisposalMethod::RESTORE_PREVIOUS};
    336  BGRAColor frameColor1 = BGRAColor::Green();
    337  RawAccessFrameRef frame1 = WithBlendAnimationFilter(
    338      decoder, params1, IntSize(100, 100),
    339      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    340        auto result = aFilter->WritePixels<uint32_t>(
    341            [&] { return AsVariant(frameColor1.AsPixel()); });
    342        EXPECT_EQ(WriteState::FINISHED, result);
    343      });
    344  EXPECT_EQ(IntRect(0, 10, 100, 80), frame1->GetDirtyRect());
    345 
    346  AnimationParams params2{
    347      IntRect(0, 40, 100, 20), FrameTimeout::FromRawMilliseconds(0),
    348      /* aFrameNum */ 2, BlendMethod::SOURCE, DisposalMethod::KEEP};
    349  BGRAColor frameColor2(0, 0, 0xFF, 0x80);
    350  RawAccessFrameRef frame2 = WithBlendAnimationFilter(
    351      decoder, params2, IntSize(100, 100),
    352      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    353        auto result = aFilter->WritePixels<uint32_t>(
    354            [&] { return AsVariant(frameColor2.AsPixel()); });
    355        EXPECT_EQ(WriteState::FINISHED, result);
    356      });
    357  EXPECT_EQ(IntRect(0, 10, 100, 80), frame2->GetDirtyRect());
    358 
    359  ASSERT_TRUE(frame2.get() != nullptr);
    360 
    361  RefPtr<SourceSurface> surface = frame2->GetSourceSurface();
    362  EXPECT_TRUE(RowsAreSolidColor(surface, 0, 40, frameColor0));
    363  EXPECT_TRUE(RowsAreSolidColor(surface, 40, 20, frameColor2));
    364  EXPECT_TRUE(RowsAreSolidColor(surface, 60, 40, frameColor0));
    365 }
    366 
    367 TEST(ImageBlendAnimationFilter, RestorePreviousClearWithSource)
    368 {
    369  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
    370  ASSERT_TRUE(decoder != nullptr);
    371 
    372  AnimationParams params0{
    373      IntRect(0, 0, 100, 100), FrameTimeout::FromRawMilliseconds(0),
    374      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
    375  BGRAColor frameColor0 = BGRAColor::Red();
    376  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
    377      decoder, params0, IntSize(100, 100),
    378      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    379        auto result = aFilter->WritePixels<uint32_t>(
    380            [&] { return AsVariant(frameColor0.AsPixel()); });
    381        EXPECT_EQ(WriteState::FINISHED, result);
    382      });
    383  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
    384 
    385  AnimationParams params1{
    386      IntRect(0, 0, 100, 20), FrameTimeout::FromRawMilliseconds(0),
    387      /* aFrameNum */ 1, BlendMethod::SOURCE, DisposalMethod::CLEAR};
    388  BGRAColor frameColor1 = BGRAColor::Blue();
    389  RawAccessFrameRef frame1 = WithBlendAnimationFilter(
    390      decoder, params1, IntSize(100, 100),
    391      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    392        auto result = aFilter->WritePixels<uint32_t>(
    393            [&] { return AsVariant(frameColor1.AsPixel()); });
    394        EXPECT_EQ(WriteState::FINISHED, result);
    395      });
    396  EXPECT_EQ(IntRect(0, 0, 100, 20), frame1->GetDirtyRect());
    397 
    398  AnimationParams params2{
    399      IntRect(0, 10, 100, 80), FrameTimeout::FromRawMilliseconds(0),
    400      /* aFrameNum */ 2, BlendMethod::SOURCE, DisposalMethod::RESTORE_PREVIOUS};
    401  BGRAColor frameColor2 = BGRAColor::Green();
    402  RawAccessFrameRef frame2 = WithBlendAnimationFilter(
    403      decoder, params2, IntSize(100, 100),
    404      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    405        auto result = aFilter->WritePixels<uint32_t>(
    406            [&] { return AsVariant(frameColor2.AsPixel()); });
    407        EXPECT_EQ(WriteState::FINISHED, result);
    408      });
    409  EXPECT_EQ(IntRect(0, 0, 100, 90), frame2->GetDirtyRect());
    410 
    411  AnimationParams params3{
    412      IntRect(0, 40, 100, 20), FrameTimeout::FromRawMilliseconds(0),
    413      /* aFrameNum */ 3, BlendMethod::SOURCE, DisposalMethod::KEEP};
    414  BGRAColor frameColor3 = BGRAColor::Blue();
    415  RawAccessFrameRef frame3 = WithBlendAnimationFilter(
    416      decoder, params3, IntSize(100, 100),
    417      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    418        auto result = aFilter->WritePixels<uint32_t>(
    419            [&] { return AsVariant(frameColor3.AsPixel()); });
    420        EXPECT_EQ(WriteState::FINISHED, result);
    421      });
    422  EXPECT_EQ(IntRect(0, 0, 100, 90), frame3->GetDirtyRect());
    423 
    424  ASSERT_TRUE(frame3.get() != nullptr);
    425 
    426  RefPtr<SourceSurface> surface = frame3->GetSourceSurface();
    427  EXPECT_TRUE(RowsAreSolidColor(surface, 0, 20, BGRAColor::Transparent()));
    428  EXPECT_TRUE(RowsAreSolidColor(surface, 20, 20, frameColor0));
    429  EXPECT_TRUE(RowsAreSolidColor(surface, 40, 20, frameColor3));
    430  EXPECT_TRUE(RowsAreSolidColor(surface, 60, 40, frameColor0));
    431 }
    432 
    433 TEST(ImageBlendAnimationFilter, PartialOverlapFrameRect)
    434 {
    435  RefPtr<image::Decoder> decoder = CreateTrivialBlendingDecoder();
    436  ASSERT_TRUE(decoder != nullptr);
    437 
    438  AnimationParams params0{
    439      IntRect(-10, -20, 110, 100), FrameTimeout::FromRawMilliseconds(0),
    440      /* aFrameNum */ 0, BlendMethod::SOURCE, DisposalMethod::KEEP};
    441  BGRAColor frameColor0 = BGRAColor::Red();
    442  RawAccessFrameRef frame0 = WithBlendAnimationFilter(
    443      decoder, params0, IntSize(100, 100),
    444      [&](image::Decoder* aDecoder, SurfaceFilter* aFilter) {
    445        auto result = aFilter->WritePixels<uint32_t>(
    446            [&] { return AsVariant(frameColor0.AsPixel()); });
    447        EXPECT_EQ(WriteState::FINISHED, result);
    448      });
    449  EXPECT_EQ(IntRect(0, 0, 100, 100), frame0->GetDirtyRect());
    450 
    451  RefPtr<SourceSurface> surface = frame0->GetSourceSurface();
    452  EXPECT_TRUE(RowsAreSolidColor(surface, 0, 80, frameColor0));
    453  EXPECT_TRUE(RowsAreSolidColor(surface, 80, 20, BGRAColor::Transparent()));
    454 }