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 }