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 }