summaryrefslogtreecommitdiffstats
path: root/image
diff options
context:
space:
mode:
Diffstat (limited to 'image')
-rw-r--r--image/moz.build2
-rw-r--r--image/test/gtest/Common.cpp673
-rw-r--r--image/test/gtest/Common.h419
-rw-r--r--image/test/gtest/TestADAM7InterpolatingFilter.cpp671
-rw-r--r--image/test/gtest/TestCopyOnWrite.cpp235
-rw-r--r--image/test/gtest/TestDecodeToSurface.cpp123
-rw-r--r--image/test/gtest/TestDecoders.cpp669
-rw-r--r--image/test/gtest/TestDeinterlacingFilter.cpp672
-rw-r--r--image/test/gtest/TestDownscalingFilter.cpp231
-rw-r--r--image/test/gtest/TestDownscalingFilterNoSkia.cpp57
-rw-r--r--image/test/gtest/TestLoader.cpp84
-rw-r--r--image/test/gtest/TestMetadata.cpp255
-rw-r--r--image/test/gtest/TestRemoveFrameRectFilter.cpp327
-rw-r--r--image/test/gtest/TestSourceBuffer.cpp810
-rw-r--r--image/test/gtest/TestStreamingLexer.cpp973
-rw-r--r--image/test/gtest/TestSurfacePipeIntegration.cpp508
-rw-r--r--image/test/gtest/TestSurfaceSink.cpp1491
-rw-r--r--image/test/gtest/animated-with-extra-image-sub-blocks.gifbin434 -> 0 bytes
-rw-r--r--image/test/gtest/corrupt-with-bad-bmp-height.icobin41663 -> 0 bytes
-rw-r--r--image/test/gtest/corrupt-with-bad-bmp-width.icobin41663 -> 0 bytes
-rw-r--r--image/test/gtest/corrupt.jpgbin2477 -> 0 bytes
-rw-r--r--image/test/gtest/downscaled.bmpbin30138 -> 0 bytes
-rw-r--r--image/test/gtest/downscaled.gifbin223 -> 0 bytes
-rw-r--r--image/test/gtest/downscaled.icobin41662 -> 0 bytes
-rw-r--r--image/test/gtest/downscaled.iconbin40003 -> 0 bytes
-rw-r--r--image/test/gtest/downscaled.jpgbin6035 -> 0 bytes
-rw-r--r--image/test/gtest/downscaled.pngbin1015 -> 0 bytes
-rw-r--r--image/test/gtest/first-frame-green.gifbin317 -> 0 bytes
-rw-r--r--image/test/gtest/first-frame-green.pngbin364 -> 0 bytes
-rw-r--r--image/test/gtest/first-frame-padding.gifbin49 -> 0 bytes
-rw-r--r--image/test/gtest/green-1x1-truncated.gifbin53 -> 0 bytes
-rw-r--r--image/test/gtest/green.bmpbin30138 -> 0 bytes
-rw-r--r--image/test/gtest/green.gifbin156 -> 0 bytes
-rw-r--r--image/test/gtest/green.icobin41662 -> 0 bytes
-rw-r--r--image/test/gtest/green.iconbin40002 -> 0 bytes
-rw-r--r--image/test/gtest/green.jpgbin361 -> 0 bytes
-rw-r--r--image/test/gtest/green.pngbin255 -> 0 bytes
-rw-r--r--image/test/gtest/invalid-truncated-metadata.bmpbin54 -> 0 bytes
-rw-r--r--image/test/gtest/moz.build79
-rw-r--r--image/test/gtest/no-frame-delay.gifbin317 -> 0 bytes
-rw-r--r--image/test/gtest/rle4.bmpbin3686 -> 0 bytes
-rw-r--r--image/test/gtest/rle8.bmpbin1288 -> 0 bytes
-rw-r--r--image/test/gtest/transparent-ico-with-and-mask.icobin3262 -> 0 bytes
-rw-r--r--image/test/gtest/transparent-if-within-ico.bmpbin4234 -> 0 bytes
-rw-r--r--image/test/gtest/transparent.gifbin355 -> 0 bytes
-rw-r--r--image/test/gtest/transparent.pngbin419 -> 0 bytes
46 files changed, 0 insertions, 8279 deletions
diff --git a/image/moz.build b/image/moz.build
index 7e7e0fe70..9eed46d31 100644
--- a/image/moz.build
+++ b/image/moz.build
@@ -5,8 +5,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
DIRS += ['build', 'decoders', 'encoders']
-if CONFIG['ENABLE_TESTS']:
- DIRS += ['test/gtest']
with Files('**'):
BUG_COMPONENT = ('Core', 'ImageLib')
diff --git a/image/test/gtest/Common.cpp b/image/test/gtest/Common.cpp
deleted file mode 100644
index 5a24bbb14..000000000
--- a/image/test/gtest/Common.cpp
+++ /dev/null
@@ -1,673 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "Common.h"
-
-#include <cstdlib>
-
-#include "nsDirectoryServiceDefs.h"
-#include "nsIDirectoryService.h"
-#include "nsIFile.h"
-#include "nsIInputStream.h"
-#include "nsIProperties.h"
-#include "nsNetUtil.h"
-#include "mozilla/RefPtr.h"
-#include "nsStreamUtils.h"
-#include "nsString.h"
-
-namespace mozilla {
-namespace image {
-
-using namespace gfx;
-
-using std::abs;
-using std::vector;
-
-///////////////////////////////////////////////////////////////////////////////
-// General Helpers
-///////////////////////////////////////////////////////////////////////////////
-
-// These macros work like gtest's ASSERT_* macros, except that they can be used
-// in functions that return values.
-#define ASSERT_TRUE_OR_RETURN(e, rv) \
- EXPECT_TRUE(e); \
- if (!(e)) { \
- return rv; \
- }
-
-#define ASSERT_EQ_OR_RETURN(a, b, rv) \
- EXPECT_EQ(a, b); \
- if ((a) != (b)) { \
- return rv; \
- }
-
-#define ASSERT_GE_OR_RETURN(a, b, rv) \
- EXPECT_GE(a, b); \
- if (!((a) >= (b))) { \
- return rv; \
- }
-
-#define ASSERT_LE_OR_RETURN(a, b, rv) \
- EXPECT_LE(a, b); \
- if (!((a) <= (b))) { \
- return rv; \
- }
-
-#define ASSERT_LT_OR_RETURN(a, b, rv) \
- EXPECT_LT(a, b); \
- if (!((a) < (b))) { \
- return rv; \
- }
-
-already_AddRefed<nsIInputStream>
-LoadFile(const char* aRelativePath)
-{
- nsresult rv;
-
- nsCOMPtr<nsIProperties> dirService =
- do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
- ASSERT_TRUE_OR_RETURN(dirService != nullptr, nullptr);
-
- // Retrieve the current working directory.
- nsCOMPtr<nsIFile> file;
- rv = dirService->Get(NS_OS_CURRENT_WORKING_DIR,
- NS_GET_IID(nsIFile), getter_AddRefs(file));
- ASSERT_TRUE_OR_RETURN(NS_SUCCEEDED(rv), nullptr);
-
- // Construct the final path by appending the working path to the current
- // working directory.
- file->AppendNative(nsDependentCString(aRelativePath));
-
- // Construct an input stream for the requested file.
- nsCOMPtr<nsIInputStream> inputStream;
- rv = NS_NewLocalFileInputStream(getter_AddRefs(inputStream), file);
- ASSERT_TRUE_OR_RETURN(NS_SUCCEEDED(rv), nullptr);
-
- // Ensure the resulting input stream is buffered.
- if (!NS_InputStreamIsBuffered(inputStream)) {
- nsCOMPtr<nsIInputStream> bufStream;
- rv = NS_NewBufferedInputStream(getter_AddRefs(bufStream),
- inputStream, 1024);
- ASSERT_TRUE_OR_RETURN(NS_SUCCEEDED(rv), nullptr);
- inputStream = bufStream;
- }
-
- return inputStream.forget();
-}
-
-bool
-IsSolidColor(SourceSurface* aSurface,
- BGRAColor aColor,
- uint8_t aFuzz /* = 0 */)
-{
- IntSize size = aSurface->GetSize();
- return RectIsSolidColor(aSurface, IntRect(0, 0, size.width, size.height),
- aColor, aFuzz);
-}
-
-bool
-IsSolidPalettedColor(Decoder* aDecoder, uint8_t aColor)
-{
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- return PalettedRectIsSolidColor(aDecoder, currentFrame->GetRect(), aColor);
-}
-
-bool
-RowsAreSolidColor(SourceSurface* aSurface,
- int32_t aStartRow,
- int32_t aRowCount,
- BGRAColor aColor,
- uint8_t aFuzz /* = 0 */)
-{
- IntSize size = aSurface->GetSize();
- return RectIsSolidColor(aSurface, IntRect(0, aStartRow, size.width, aRowCount),
- aColor, aFuzz);
-}
-
-bool
-PalettedRowsAreSolidColor(Decoder* aDecoder,
- int32_t aStartRow,
- int32_t aRowCount,
- uint8_t aColor)
-{
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- IntRect frameRect = currentFrame->GetRect();
- IntRect solidColorRect(frameRect.x, aStartRow, frameRect.width, aRowCount);
- return PalettedRectIsSolidColor(aDecoder, solidColorRect, aColor);
-}
-
-bool
-RectIsSolidColor(SourceSurface* aSurface,
- const IntRect& aRect,
- BGRAColor aColor,
- uint8_t aFuzz /* = 0 */)
-{
- IntSize surfaceSize = aSurface->GetSize();
- IntRect rect =
- aRect.Intersect(IntRect(0, 0, surfaceSize.width, surfaceSize.height));
-
- RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
- ASSERT_TRUE_OR_RETURN(dataSurface != nullptr, false);
-
- ASSERT_EQ_OR_RETURN(dataSurface->Stride(), surfaceSize.width * 4, false);
-
- DataSourceSurface::ScopedMap mapping(dataSurface,
- DataSourceSurface::MapType::READ);
- ASSERT_TRUE_OR_RETURN(mapping.IsMapped(), false);
-
- uint8_t* data = dataSurface->GetData();
- ASSERT_TRUE_OR_RETURN(data != nullptr, false);
-
- int32_t rowLength = dataSurface->Stride();
- for (int32_t row = rect.y; row < rect.YMost(); ++row) {
- for (int32_t col = rect.x; col < rect.XMost(); ++col) {
- int32_t i = row * rowLength + col * 4;
- if (aFuzz != 0) {
- ASSERT_LE_OR_RETURN(abs(aColor.mBlue - data[i + 0]), aFuzz, false);
- ASSERT_LE_OR_RETURN(abs(aColor.mGreen - data[i + 1]), aFuzz, false);
- ASSERT_LE_OR_RETURN(abs(aColor.mRed - data[i + 2]), aFuzz, false);
- ASSERT_LE_OR_RETURN(abs(aColor.mAlpha - data[i + 3]), aFuzz, false);
- } else {
- ASSERT_EQ_OR_RETURN(aColor.mBlue, data[i + 0], false);
- ASSERT_EQ_OR_RETURN(aColor.mGreen, data[i + 1], false);
- ASSERT_EQ_OR_RETURN(aColor.mRed, data[i + 2], false);
- ASSERT_EQ_OR_RETURN(aColor.mAlpha, data[i + 3], false);
- }
- }
- }
-
- return true;
-}
-
-bool
-PalettedRectIsSolidColor(Decoder* aDecoder, const IntRect& aRect, uint8_t aColor)
-{
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- uint8_t* imageData;
- uint32_t imageLength;
- currentFrame->GetImageData(&imageData, &imageLength);
- ASSERT_TRUE_OR_RETURN(imageData, false);
-
- // Clamp to the frame rect. If any pixels outside the frame rect are included,
- // we immediately fail, because such pixels don't have any "color" in the
- // sense this function measures - they're transparent, and that doesn't
- // necessarily correspond to any color palette index at all.
- IntRect frameRect = currentFrame->GetRect();
- ASSERT_EQ_OR_RETURN(imageLength, uint32_t(frameRect.Area()), false);
- IntRect rect = aRect.Intersect(frameRect);
- ASSERT_EQ_OR_RETURN(rect.Area(), aRect.Area(), false);
-
- // Translate |rect| by |frameRect.TopLeft()| to reflect the fact that the
- // frame rect's offset doesn't actually mean anything in terms of the
- // in-memory representation of the surface. The image data starts at the upper
- // left corner of the frame rect, in other words.
- rect -= frameRect.TopLeft();
-
- // Walk through the image data and make sure that the entire rect has the
- // palette index |aColor|.
- int32_t rowLength = frameRect.width;
- for (int32_t row = rect.y; row < rect.YMost(); ++row) {
- for (int32_t col = rect.x; col < rect.XMost(); ++col) {
- int32_t i = row * rowLength + col;
- ASSERT_EQ_OR_RETURN(aColor, imageData[i], false);
- }
- }
-
- return true;
-}
-
-bool
-RowHasPixels(SourceSurface* aSurface,
- int32_t aRow,
- const vector<BGRAColor>& aPixels)
-{
- ASSERT_GE_OR_RETURN(aRow, 0, false);
-
- IntSize surfaceSize = aSurface->GetSize();
- ASSERT_EQ_OR_RETURN(aPixels.size(), size_t(surfaceSize.width), false);
- ASSERT_LT_OR_RETURN(aRow, surfaceSize.height, false);
-
- RefPtr<DataSourceSurface> dataSurface = aSurface->GetDataSurface();
- ASSERT_TRUE_OR_RETURN(dataSurface, false);
-
- ASSERT_EQ_OR_RETURN(dataSurface->Stride(), surfaceSize.width * 4, false);
-
- DataSourceSurface::ScopedMap mapping(dataSurface,
- DataSourceSurface::MapType::READ);
- ASSERT_TRUE_OR_RETURN(mapping.IsMapped(), false);
-
- uint8_t* data = dataSurface->GetData();
- ASSERT_TRUE_OR_RETURN(data != nullptr, false);
-
- int32_t rowLength = dataSurface->Stride();
- for (int32_t col = 0; col < surfaceSize.width; ++col) {
- int32_t i = aRow * rowLength + col * 4;
- ASSERT_EQ_OR_RETURN(aPixels[col].mBlue, data[i + 0], false);
- ASSERT_EQ_OR_RETURN(aPixels[col].mGreen, data[i + 1], false);
- ASSERT_EQ_OR_RETURN(aPixels[col].mRed, data[i + 2], false);
- ASSERT_EQ_OR_RETURN(aPixels[col].mAlpha, data[i + 3], false);
- }
-
- return true;
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// SurfacePipe Helpers
-///////////////////////////////////////////////////////////////////////////////
-
-already_AddRefed<Decoder>
-CreateTrivialDecoder()
-{
- gfxPrefs::GetSingleton();
- DecoderType decoderType = DecoderFactory::GetDecoderType("image/gif");
- NotNull<RefPtr<SourceBuffer>> sourceBuffer = WrapNotNull(new SourceBuffer());
- RefPtr<Decoder> decoder =
- DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(),
- DefaultSurfaceFlags());
- return decoder.forget();
-}
-
-void
-AssertCorrectPipelineFinalState(SurfaceFilter* aFilter,
- const gfx::IntRect& aInputSpaceRect,
- const gfx::IntRect& aOutputSpaceRect)
-{
- EXPECT_TRUE(aFilter->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(aInputSpaceRect, invalidRect->mInputSpaceRect);
- EXPECT_EQ(aOutputSpaceRect, invalidRect->mOutputSpaceRect);
-}
-
-void
-CheckGeneratedImage(Decoder* aDecoder,
- const IntRect& aRect,
- uint8_t aFuzz /* = 0 */)
-{
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- const IntSize surfaceSize = surface->GetSize();
-
- // This diagram shows how the surface is divided into regions that the code
- // below tests for the correct content. The output rect is the bounds of the
- // region labeled 'C'.
- //
- // +---------------------------+
- // | A |
- // +---------+--------+--------+
- // | B | C | D |
- // +---------+--------+--------+
- // | E |
- // +---------------------------+
-
- // Check that the output rect itself is green. (Region 'C'.)
- EXPECT_TRUE(RectIsSolidColor(surface, aRect, BGRAColor::Green(), aFuzz));
-
- // Check that the area above the output rect is transparent. (Region 'A'.)
- EXPECT_TRUE(RectIsSolidColor(surface,
- IntRect(0, 0, surfaceSize.width, aRect.y),
- BGRAColor::Transparent(), aFuzz));
-
- // Check that the area to the left of the output rect is transparent. (Region 'B'.)
- EXPECT_TRUE(RectIsSolidColor(surface,
- IntRect(0, aRect.y, aRect.x, aRect.YMost()),
- BGRAColor::Transparent(), aFuzz));
-
- // Check that the area to the right of the output rect is transparent. (Region 'D'.)
- const int32_t widthOnRight = surfaceSize.width - aRect.XMost();
- EXPECT_TRUE(RectIsSolidColor(surface,
- IntRect(aRect.XMost(), aRect.y, widthOnRight, aRect.YMost()),
- BGRAColor::Transparent(), aFuzz));
-
- // Check that the area below the output rect is transparent. (Region 'E'.)
- const int32_t heightBelow = surfaceSize.height - aRect.YMost();
- EXPECT_TRUE(RectIsSolidColor(surface,
- IntRect(0, aRect.YMost(), surfaceSize.width, heightBelow),
- BGRAColor::Transparent(), aFuzz));
-}
-
-void
-CheckGeneratedPalettedImage(Decoder* aDecoder, const IntRect& aRect)
-{
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- IntSize imageSize = currentFrame->GetImageSize();
-
- // This diagram shows how the surface is divided into regions that the code
- // below tests for the correct content. The output rect is the bounds of the
- // region labeled 'C'.
- //
- // +---------------------------+
- // | A |
- // +---------+--------+--------+
- // | B | C | D |
- // +---------+--------+--------+
- // | E |
- // +---------------------------+
-
- // Check that the output rect itself is all 255's. (Region 'C'.)
- EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder, aRect, 255));
-
- // Check that the area above the output rect is all 0's. (Region 'A'.)
- EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder,
- IntRect(0, 0, imageSize.width, aRect.y),
- 0));
-
- // Check that the area to the left of the output rect is all 0's. (Region 'B'.)
- EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder,
- IntRect(0, aRect.y, aRect.x, aRect.YMost()),
- 0));
-
- // Check that the area to the right of the output rect is all 0's. (Region 'D'.)
- const int32_t widthOnRight = imageSize.width - aRect.XMost();
- EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder,
- IntRect(aRect.XMost(), aRect.y, widthOnRight, aRect.YMost()),
- 0));
-
- // Check that the area below the output rect is transparent. (Region 'E'.)
- const int32_t heightBelow = imageSize.height - aRect.YMost();
- EXPECT_TRUE(PalettedRectIsSolidColor(aDecoder,
- IntRect(0, aRect.YMost(), imageSize.width, heightBelow),
- 0));
-}
-
-void
-CheckWritePixels(Decoder* aDecoder,
- SurfaceFilter* aFilter,
- Maybe<IntRect> aOutputRect /* = Nothing() */,
- Maybe<IntRect> aInputRect /* = Nothing() */,
- Maybe<IntRect> aInputWriteRect /* = Nothing() */,
- Maybe<IntRect> aOutputWriteRect /* = Nothing() */,
- uint8_t aFuzz /* = 0 */)
-{
- IntRect outputRect = aOutputRect.valueOr(IntRect(0, 0, 100, 100));
- IntRect inputRect = aInputRect.valueOr(IntRect(0, 0, 100, 100));
- IntRect inputWriteRect = aInputWriteRect.valueOr(inputRect);
- IntRect outputWriteRect = aOutputWriteRect.valueOr(outputRect);
-
- // Fill the image.
- int32_t count = 0;
- auto result = aFilter->WritePixels<uint32_t>([&] {
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(inputWriteRect.width * inputWriteRect.height, count);
-
- AssertCorrectPipelineFinalState(aFilter, inputRect, outputRect);
-
- // Attempt to write more data and make sure nothing changes.
- const int32_t oldCount = count;
- result = aFilter->WritePixels<uint32_t>([&] {
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(oldCount, count);
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_TRUE(aFilter->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Attempt to advance to the next row and make sure nothing changes.
- aFilter->AdvanceRow();
- EXPECT_TRUE(aFilter->IsSurfaceFinished());
- invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Check that the generated image is correct.
- CheckGeneratedImage(aDecoder, outputWriteRect, aFuzz);
-}
-
-void
-CheckPalettedWritePixels(Decoder* aDecoder,
- SurfaceFilter* aFilter,
- Maybe<IntRect> aOutputRect /* = Nothing() */,
- Maybe<IntRect> aInputRect /* = Nothing() */,
- Maybe<IntRect> aInputWriteRect /* = Nothing() */,
- Maybe<IntRect> aOutputWriteRect /* = Nothing() */,
- uint8_t aFuzz /* = 0 */)
-{
- IntRect outputRect = aOutputRect.valueOr(IntRect(0, 0, 100, 100));
- IntRect inputRect = aInputRect.valueOr(IntRect(0, 0, 100, 100));
- IntRect inputWriteRect = aInputWriteRect.valueOr(inputRect);
- IntRect outputWriteRect = aOutputWriteRect.valueOr(outputRect);
-
- // Fill the image.
- int32_t count = 0;
- auto result = aFilter->WritePixels<uint8_t>([&] {
- ++count;
- return AsVariant(uint8_t(255));
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(inputWriteRect.width * inputWriteRect.height, count);
-
- AssertCorrectPipelineFinalState(aFilter, inputRect, outputRect);
-
- // Attempt to write more data and make sure nothing changes.
- const int32_t oldCount = count;
- result = aFilter->WritePixels<uint8_t>([&] {
- ++count;
- return AsVariant(uint8_t(255));
- });
- EXPECT_EQ(oldCount, count);
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_TRUE(aFilter->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Attempt to advance to the next row and make sure nothing changes.
- aFilter->AdvanceRow();
- EXPECT_TRUE(aFilter->IsSurfaceFinished());
- invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Check that the generated image is correct.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- uint8_t* imageData;
- uint32_t imageLength;
- currentFrame->GetImageData(&imageData, &imageLength);
- ASSERT_TRUE(imageData != nullptr);
- ASSERT_EQ(outputWriteRect.width * outputWriteRect.height, int32_t(imageLength));
- for (uint32_t i = 0; i < imageLength; ++i) {
- ASSERT_EQ(uint8_t(255), imageData[i]);
- }
-}
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Test Data
-///////////////////////////////////////////////////////////////////////////////
-
-ImageTestCase GreenPNGTestCase()
-{
- return ImageTestCase("green.png", "image/png", IntSize(100, 100));
-}
-
-ImageTestCase GreenGIFTestCase()
-{
- return ImageTestCase("green.gif", "image/gif", IntSize(100, 100));
-}
-
-ImageTestCase GreenJPGTestCase()
-{
- return ImageTestCase("green.jpg", "image/jpeg", IntSize(100, 100),
- TEST_CASE_IS_FUZZY);
-}
-
-ImageTestCase GreenBMPTestCase()
-{
- return ImageTestCase("green.bmp", "image/bmp", IntSize(100, 100));
-}
-
-ImageTestCase GreenICOTestCase()
-{
- // This ICO contains a 32-bit BMP, and we use a BMP's alpha data by default
- // when the BMP is embedded in an ICO, so it's transparent.
- return ImageTestCase("green.ico", "image/x-icon", IntSize(100, 100),
- TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase GreenIconTestCase()
-{
- return ImageTestCase("green.icon", "image/icon", IntSize(100, 100),
- TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase GreenFirstFrameAnimatedGIFTestCase()
-{
- return ImageTestCase("first-frame-green.gif", "image/gif", IntSize(100, 100),
- TEST_CASE_IS_ANIMATED);
-}
-
-ImageTestCase GreenFirstFrameAnimatedPNGTestCase()
-{
- return ImageTestCase("first-frame-green.png", "image/png", IntSize(100, 100),
- TEST_CASE_IS_TRANSPARENT | TEST_CASE_IS_ANIMATED);
-}
-
-ImageTestCase CorruptTestCase()
-{
- return ImageTestCase("corrupt.jpg", "image/jpeg", IntSize(100, 100),
- TEST_CASE_HAS_ERROR);
-}
-
-ImageTestCase CorruptBMPWithTruncatedHeader()
-{
- // This BMP has a header which is truncated right between the BIH and the
- // bitfields, which is a particularly error-prone place w.r.t. the BMP decoder
- // state machine.
- return ImageTestCase("invalid-truncated-metadata.bmp", "image/bmp",
- IntSize(100, 100), TEST_CASE_HAS_ERROR);
-}
-
-ImageTestCase CorruptICOWithBadBMPWidthTestCase()
-{
- // This ICO contains a BMP icon which has a width that doesn't match the size
- // listed in the corresponding ICO directory entry.
- return ImageTestCase("corrupt-with-bad-bmp-width.ico", "image/x-icon",
- IntSize(100, 100), TEST_CASE_HAS_ERROR);
-}
-
-ImageTestCase CorruptICOWithBadBMPHeightTestCase()
-{
- // This ICO contains a BMP icon which has a height that doesn't match the size
- // listed in the corresponding ICO directory entry.
- return ImageTestCase("corrupt-with-bad-bmp-height.ico", "image/x-icon",
- IntSize(100, 100), TEST_CASE_HAS_ERROR);
-}
-
-ImageTestCase TransparentPNGTestCase()
-{
- return ImageTestCase("transparent.png", "image/png", IntSize(32, 32),
- TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase TransparentGIFTestCase()
-{
- return ImageTestCase("transparent.gif", "image/gif", IntSize(16, 16),
- TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase FirstFramePaddingGIFTestCase()
-{
- return ImageTestCase("transparent.gif", "image/gif", IntSize(16, 16),
- TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase TransparentIfWithinICOBMPTestCase(TestCaseFlags aFlags)
-{
- // This is a BMP that is only transparent when decoded as if it is within an
- // ICO file. (Note: aFlags needs to be set to TEST_CASE_DEFAULT_FLAGS or
- // TEST_CASE_IS_TRANSPARENT accordingly.)
- return ImageTestCase("transparent-if-within-ico.bmp", "image/bmp",
- IntSize(32, 32), aFlags);
-}
-
-ImageTestCase RLE4BMPTestCase()
-{
- return ImageTestCase("rle4.bmp", "image/bmp", IntSize(320, 240),
- TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase RLE8BMPTestCase()
-{
- return ImageTestCase("rle8.bmp", "image/bmp", IntSize(32, 32),
- TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase NoFrameDelayGIFTestCase()
-{
- // This is an invalid (or at least, questionably valid) GIF that's animated
- // even though it specifies a frame delay of zero. It's animated, but it's not
- // marked TEST_CASE_IS_ANIMATED because the metadata decoder can't detect that
- // it's animated.
- return ImageTestCase("no-frame-delay.gif", "image/gif", IntSize(100, 100));
-}
-
-ImageTestCase ExtraImageSubBlocksAnimatedGIFTestCase()
-{
- // This is a corrupt GIF that has extra image sub blocks between the first and
- // second frame.
- return ImageTestCase("animated-with-extra-image-sub-blocks.gif", "image/gif",
- IntSize(100, 100));
-}
-
-ImageTestCase DownscaledPNGTestCase()
-{
- // This testcase (and all the other "downscaled") testcases) consists of 25
- // lines of green, followed by 25 lines of red, followed by 25 lines of green,
- // followed by 25 more lines of red. It's intended that tests downscale it
- // from 100x100 to 20x20, so we specify a 20x20 output size.
- return ImageTestCase("downscaled.png", "image/png", IntSize(100, 100),
- IntSize(20, 20));
-}
-
-ImageTestCase DownscaledGIFTestCase()
-{
- return ImageTestCase("downscaled.gif", "image/gif", IntSize(100, 100),
- IntSize(20, 20));
-}
-
-ImageTestCase DownscaledJPGTestCase()
-{
- return ImageTestCase("downscaled.jpg", "image/jpeg", IntSize(100, 100),
- IntSize(20, 20));
-}
-
-ImageTestCase DownscaledBMPTestCase()
-{
- return ImageTestCase("downscaled.bmp", "image/bmp", IntSize(100, 100),
- IntSize(20, 20));
-}
-
-ImageTestCase DownscaledICOTestCase()
-{
- return ImageTestCase("downscaled.ico", "image/x-icon", IntSize(100, 100),
- IntSize(20, 20), TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase DownscaledIconTestCase()
-{
- return ImageTestCase("downscaled.icon", "image/icon", IntSize(100, 100),
- IntSize(20, 20), TEST_CASE_IS_TRANSPARENT);
-}
-
-ImageTestCase DownscaledTransparentICOWithANDMaskTestCase()
-{
- // This test case is an ICO with AND mask transparency. We want to ensure that
- // we can downscale it without crashing or triggering ASAN failures, but its
- // content isn't simple to verify, so for now we don't check the output.
- return ImageTestCase("transparent-ico-with-and-mask.ico", "image/x-icon",
- IntSize(32, 32), IntSize(20, 20),
- TEST_CASE_IS_TRANSPARENT | TEST_CASE_IGNORE_OUTPUT);
-}
-
-ImageTestCase TruncatedSmallGIFTestCase()
-{
- return ImageTestCase("green-1x1-truncated.gif", "image/gif", IntSize(1, 1));
-}
-
-} // namespace image
-} // namespace mozilla
diff --git a/image/test/gtest/Common.h b/image/test/gtest/Common.h
deleted file mode 100644
index 0c288cddc..000000000
--- a/image/test/gtest/Common.h
+++ /dev/null
@@ -1,419 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#ifndef mozilla_image_test_gtest_Common_h
-#define mozilla_image_test_gtest_Common_h
-
-#include <vector>
-
-#include "gtest/gtest.h"
-
-#include "mozilla/Maybe.h"
-#include "mozilla/UniquePtr.h"
-#include "mozilla/gfx/2D.h"
-#include "Decoder.h"
-#include "gfxColor.h"
-#include "imgITools.h"
-#include "nsCOMPtr.h"
-#include "SurfacePipe.h"
-#include "SurfacePipeFactory.h"
-
-class nsIInputStream;
-
-namespace mozilla {
-namespace image {
-
-///////////////////////////////////////////////////////////////////////////////
-// Types
-///////////////////////////////////////////////////////////////////////////////
-
-enum TestCaseFlags
-{
- TEST_CASE_DEFAULT_FLAGS = 0,
- TEST_CASE_IS_FUZZY = 1 << 0,
- TEST_CASE_HAS_ERROR = 1 << 1,
- TEST_CASE_IS_TRANSPARENT = 1 << 2,
- TEST_CASE_IS_ANIMATED = 1 << 3,
- TEST_CASE_IGNORE_OUTPUT = 1 << 4,
-};
-
-struct ImageTestCase
-{
- ImageTestCase(const char* aPath,
- const char* aMimeType,
- gfx::IntSize aSize,
- uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
- : mPath(aPath)
- , mMimeType(aMimeType)
- , mSize(aSize)
- , mOutputSize(aSize)
- , mFlags(aFlags)
- { }
-
- ImageTestCase(const char* aPath,
- const char* aMimeType,
- gfx::IntSize aSize,
- gfx::IntSize aOutputSize,
- uint32_t aFlags = TEST_CASE_DEFAULT_FLAGS)
- : mPath(aPath)
- , mMimeType(aMimeType)
- , mSize(aSize)
- , mOutputSize(aOutputSize)
- , mFlags(aFlags)
- { }
-
- const char* mPath;
- const char* mMimeType;
- gfx::IntSize mSize;
- gfx::IntSize mOutputSize;
- uint32_t mFlags;
-};
-
-struct BGRAColor
-{
- BGRAColor() : BGRAColor(0, 0, 0, 0) { }
-
- BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha)
- : mBlue(aBlue)
- , mGreen(aGreen)
- , mRed(aRed)
- , mAlpha(aAlpha)
- { }
-
- static BGRAColor Green() { return BGRAColor(0x00, 0xFF, 0x00, 0xFF); }
- static BGRAColor Red() { return BGRAColor(0x00, 0x00, 0xFF, 0xFF); }
- static BGRAColor Blue() { return BGRAColor(0xFF, 0x00, 0x00, 0xFF); }
- static BGRAColor Transparent() { return BGRAColor(0x00, 0x00, 0x00, 0x00); }
-
- uint32_t AsPixel() const { return gfxPackedPixel(mAlpha, mRed, mGreen, mBlue); }
-
- uint8_t mBlue;
- uint8_t mGreen;
- uint8_t mRed;
- uint8_t mAlpha;
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// General Helpers
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * A RAII class that ensure that ImageLib services are available. Any tests that
- * require ImageLib to be initialized (for example, any test that uses the
- * SurfaceCache; see image::EnsureModuleInitialized() for the full list) can
- * use this class to ensure that ImageLib services are available. Failure to do
- * so can result in strange, non-deterministic failures.
- */
-struct AutoInitializeImageLib
-{
- AutoInitializeImageLib()
- {
- // Ensure that ImageLib services are initialized.
- nsCOMPtr<imgITools> imgTools = do_CreateInstance("@mozilla.org/image/tools;1");
- EXPECT_TRUE(imgTools != nullptr);
- }
-};
-
-/// Loads a file from the current directory. @return an nsIInputStream for it.
-already_AddRefed<nsIInputStream> LoadFile(const char* aRelativePath);
-
-/**
- * @returns true if every pixel of @aSurface is @aColor.
- *
- * If @aFuzz is nonzero, a tolerance of @aFuzz is allowed in each color
- * component. This may be necessary for tests that involve JPEG images or
- * downscaling.
- */
-bool IsSolidColor(gfx::SourceSurface* aSurface,
- BGRAColor aColor,
- uint8_t aFuzz = 0);
-
-/**
- * @returns true if every pixel of @aDecoder's surface has the palette index
- * specified by @aColor.
- */
-bool IsSolidPalettedColor(Decoder* aDecoder, uint8_t aColor);
-
-/**
- * @returns true if every pixel in the range of rows specified by @aStartRow and
- * @aRowCount of @aSurface is @aColor.
- *
- * If @aFuzz is nonzero, a tolerance of @aFuzz is allowed in each color
- * component. This may be necessary for tests that involve JPEG images or
- * downscaling.
- */
-bool RowsAreSolidColor(gfx::SourceSurface* aSurface,
- int32_t aStartRow,
- int32_t aRowCount,
- BGRAColor aColor,
- uint8_t aFuzz = 0);
-
-/**
- * @returns true if every pixel in the range of rows specified by @aStartRow and
- * @aRowCount of @aDecoder's surface has the palette index specified by @aColor.
- */
-bool PalettedRowsAreSolidColor(Decoder* aDecoder,
- int32_t aStartRow,
- int32_t aRowCount,
- uint8_t aColor);
-
-/**
- * @returns true if every pixel in the rect specified by @aRect is @aColor.
- *
- * If @aFuzz is nonzero, a tolerance of @aFuzz is allowed in each color
- * component. This may be necessary for tests that involve JPEG images or
- * downscaling.
- */
-bool RectIsSolidColor(gfx::SourceSurface* aSurface,
- const gfx::IntRect& aRect,
- BGRAColor aColor,
- uint8_t aFuzz = 0);
-
-/**
- * @returns true if every pixel in the rect specified by @aRect has the palette
- * index specified by @aColor.
- */
-bool PalettedRectIsSolidColor(Decoder* aDecoder,
- const gfx::IntRect& aRect,
- uint8_t aColor);
-
-/**
- * @returns true if the pixels in @aRow of @aSurface match the pixels given in
- * @aPixels.
- */
-bool RowHasPixels(gfx::SourceSurface* aSurface,
- int32_t aRow,
- const std::vector<BGRAColor>& aPixels);
-
-// ExpectNoResume is an IResumable implementation for use by tests that expect
-// Resume() to never get called.
-class ExpectNoResume final : public IResumable
-{
-public:
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ExpectNoResume, override)
-
- void Resume() override { FAIL() << "Resume() should not get called"; }
-
-private:
- ~ExpectNoResume() override { }
-};
-
-// CountResumes is an IResumable implementation for use by tests that expect
-// Resume() to get called a certain number of times.
-class CountResumes : public IResumable
-{
-public:
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(CountResumes, override)
-
- CountResumes() : mCount(0) { }
-
- void Resume() override { mCount++; }
- uint32_t Count() const { return mCount; }
-
-private:
- ~CountResumes() override { }
-
- uint32_t mCount;
-};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// SurfacePipe Helpers
-///////////////////////////////////////////////////////////////////////////////
-
-/**
- * Creates a decoder with no data associated with, suitable for testing code
- * that requires a decoder to initialize or to allocate surfaces but doesn't
- * actually need the decoder to do any decoding.
- *
- * XXX(seth): We only need this because SurfaceSink and PalettedSurfaceSink
- * defer to the decoder for surface allocation. Once all decoders use
- * SurfacePipe we won't need to do that anymore and we can remove this function.
- */
-already_AddRefed<Decoder> CreateTrivialDecoder();
-
-/**
- * Creates a pipeline of SurfaceFilters from a list of Config structs and passes
- * it to the provided lambda @aFunc. Assertions that the pipeline is constructly
- * correctly and cleanup of any allocated surfaces is handled automatically.
- *
- * @param aDecoder The decoder to use for allocating surfaces.
- * @param aFunc The lambda function to pass the filter pipeline to.
- * @param aConfigs The configuration for the pipeline.
- */
-template <typename Func, typename... Configs>
-void WithFilterPipeline(Decoder* aDecoder, Func aFunc, const Configs&... aConfigs)
-{
- auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
- nsresult rv = pipe->Configure(aConfigs...);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- aFunc(aDecoder, pipe.get());
-
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- if (currentFrame) {
- currentFrame->Finish();
- }
-}
-
-/**
- * Creates a pipeline of SurfaceFilters from a list of Config structs and
- * asserts that configuring it fails. Cleanup of any allocated surfaces is
- * handled automatically.
- *
- * @param aDecoder The decoder to use for allocating surfaces.
- * @param aConfigs The configuration for the pipeline.
- */
-template <typename... Configs>
-void AssertConfiguringPipelineFails(Decoder* aDecoder, const Configs&... aConfigs)
-{
- auto pipe = MakeUnique<typename detail::FilterPipeline<Configs...>::Type>();
- nsresult rv = pipe->Configure(aConfigs...);
-
- // Callers expect configuring the pipeline to fail.
- ASSERT_TRUE(NS_FAILED(rv));
-
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- if (currentFrame) {
- currentFrame->Finish();
- }
-}
-
-/**
- * Asserts that the provided filter pipeline is in the correct final state,
- * which is to say, the entire surface has been written to (IsSurfaceFinished()
- * returns true) and the invalid rects are as expected.
- *
- * @param aFilter The filter pipeline to check.
- * @param aInputSpaceRect The expect invalid rect, in input space.
- * @param aoutputSpaceRect The expect invalid rect, in output space.
- */
-void AssertCorrectPipelineFinalState(SurfaceFilter* aFilter,
- const gfx::IntRect& aInputSpaceRect,
- const gfx::IntRect& aOutputSpaceRect);
-
-/**
- * Checks a generated image for correctness. Reports any unexpected deviation
- * from the expected image as GTest failures.
- *
- * @param aDecoder The decoder which contains the image. The decoder's current
- * frame will be checked.
- * @param aRect The region in the space of the output surface that the filter
- * pipeline will actually write to. It's expected that pixels in
- * this region are green, while pixels outside this region are
- * transparent.
- * @param aFuzz The amount of fuzz to use in pixel comparisons.
- */
-void CheckGeneratedImage(Decoder* aDecoder,
- const gfx::IntRect& aRect,
- uint8_t aFuzz = 0);
-
-/**
- * Checks a generated paletted image for correctness. Reports any unexpected
- * deviation from the expected image as GTest failures.
- *
- * @param aDecoder The decoder which contains the image. The decoder's current
- * frame will be checked.
- * @param aRect The region in the space of the output surface that the filter
- * pipeline will actually write to. It's expected that pixels in
- * this region have a palette index of 255, while pixels outside
- * this region have a palette index of 0.
- */
-void CheckGeneratedPalettedImage(Decoder* aDecoder, const gfx::IntRect& aRect);
-
-/**
- * Tests the result of calling WritePixels() using the provided SurfaceFilter
- * pipeline. The pipeline must be a normal (i.e., non-paletted) pipeline.
- *
- * The arguments are specified in the an order intended to minimize the number
- * of arguments that most test cases need to pass.
- *
- * @param aDecoder The decoder whose current frame will be written to.
- * @param aFilter The SurfaceFilter pipeline to use.
- * @param aOutputRect The region in the space of the output surface that will be
- * invalidated by the filter pipeline. Defaults to
- * (0, 0, 100, 100).
- * @param aInputRect The region in the space of the input image that will be
- * invalidated by the filter pipeline. Defaults to
- * (0, 0, 100, 100).
- * @param aInputWriteRect The region in the space of the input image that the
- * filter pipeline will allow writes to. Note the
- * difference from @aInputRect: @aInputRect is the actual
- * region invalidated, while @aInputWriteRect is the
- * region that is written to. These can differ in cases
- * where the input is not clipped to the size of the image.
- * Defaults to the entire input rect.
- * @param aOutputWriteRect The region in the space of the output surface that
- * the filter pipeline will actually write to. It's
- * expected that pixels in this region are green, while
- * pixels outside this region are transparent. Defaults
- * to the entire output rect.
- */
-void CheckWritePixels(Decoder* aDecoder,
- SurfaceFilter* aFilter,
- Maybe<gfx::IntRect> aOutputRect = Nothing(),
- Maybe<gfx::IntRect> aInputRect = Nothing(),
- Maybe<gfx::IntRect> aInputWriteRect = Nothing(),
- Maybe<gfx::IntRect> aOutputWriteRect = Nothing(),
- uint8_t aFuzz = 0);
-
-/**
- * Tests the result of calling WritePixels() using the provided SurfaceFilter
- * pipeline. The pipeline must be a paletted pipeline.
- * @see CheckWritePixels() for documentation of the arguments.
- */
-void CheckPalettedWritePixels(Decoder* aDecoder,
- SurfaceFilter* aFilter,
- Maybe<gfx::IntRect> aOutputRect = Nothing(),
- Maybe<gfx::IntRect> aInputRect = Nothing(),
- Maybe<gfx::IntRect> aInputWriteRect = Nothing(),
- Maybe<gfx::IntRect> aOutputWriteRect = Nothing(),
- uint8_t aFuzz = 0);
-
-
-///////////////////////////////////////////////////////////////////////////////
-// Test Data
-///////////////////////////////////////////////////////////////////////////////
-
-ImageTestCase GreenPNGTestCase();
-ImageTestCase GreenGIFTestCase();
-ImageTestCase GreenJPGTestCase();
-ImageTestCase GreenBMPTestCase();
-ImageTestCase GreenICOTestCase();
-ImageTestCase GreenIconTestCase();
-
-ImageTestCase GreenFirstFrameAnimatedGIFTestCase();
-ImageTestCase GreenFirstFrameAnimatedPNGTestCase();
-
-ImageTestCase CorruptTestCase();
-ImageTestCase CorruptBMPWithTruncatedHeader();
-ImageTestCase CorruptICOWithBadBMPWidthTestCase();
-ImageTestCase CorruptICOWithBadBMPHeightTestCase();
-
-ImageTestCase TransparentPNGTestCase();
-ImageTestCase TransparentGIFTestCase();
-ImageTestCase FirstFramePaddingGIFTestCase();
-ImageTestCase NoFrameDelayGIFTestCase();
-ImageTestCase ExtraImageSubBlocksAnimatedGIFTestCase();
-
-ImageTestCase TransparentBMPWhenBMPAlphaEnabledTestCase();
-ImageTestCase RLE4BMPTestCase();
-ImageTestCase RLE8BMPTestCase();
-
-ImageTestCase DownscaledPNGTestCase();
-ImageTestCase DownscaledGIFTestCase();
-ImageTestCase DownscaledJPGTestCase();
-ImageTestCase DownscaledBMPTestCase();
-ImageTestCase DownscaledICOTestCase();
-ImageTestCase DownscaledIconTestCase();
-ImageTestCase DownscaledTransparentICOWithANDMaskTestCase();
-
-ImageTestCase TruncatedSmallGIFTestCase();
-
-} // namespace image
-} // namespace mozilla
-
-#endif // mozilla_image_test_gtest_Common_h
diff --git a/image/test/gtest/TestADAM7InterpolatingFilter.cpp b/image/test/gtest/TestADAM7InterpolatingFilter.cpp
deleted file mode 100644
index d11224251..000000000
--- a/image/test/gtest/TestADAM7InterpolatingFilter.cpp
+++ /dev/null
@@ -1,671 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include <algorithm>
-#include <vector>
-
-#include "gtest/gtest.h"
-
-#include "mozilla/gfx/2D.h"
-#include "mozilla/Maybe.h"
-#include "Common.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "SourceBuffer.h"
-#include "SurfaceFilters.h"
-#include "SurfacePipe.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-using std::generate;
-using std::vector;
-
-template <typename Func> void
-WithADAM7InterpolatingFilter(const IntSize& aSize, Func aFunc)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(bool(decoder));
-
- WithFilterPipeline(decoder, Forward<Func>(aFunc),
- ADAM7InterpolatingConfig { },
- SurfaceConfig { decoder, aSize,
- SurfaceFormat::B8G8R8A8, false });
-}
-
-void
-AssertConfiguringADAM7InterpolatingFilterFails(const IntSize& aSize)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(bool(decoder));
-
- AssertConfiguringPipelineFails(decoder,
- ADAM7InterpolatingConfig { },
- SurfaceConfig { decoder, aSize,
- SurfaceFormat::B8G8R8A8, false });
-}
-
-uint8_t
-InterpolateByte(uint8_t aByteA, uint8_t aByteB, float aWeight)
-{
- return uint8_t(aByteA * aWeight + aByteB * (1.0f - aWeight));
-}
-
-BGRAColor
-InterpolateColors(BGRAColor aColor1, BGRAColor aColor2, float aWeight)
-{
- return BGRAColor(InterpolateByte(aColor1.mBlue, aColor2.mBlue, aWeight),
- InterpolateByte(aColor1.mGreen, aColor2.mGreen, aWeight),
- InterpolateByte(aColor1.mRed, aColor2.mRed, aWeight),
- InterpolateByte(aColor1.mAlpha, aColor2.mAlpha, aWeight));
-}
-
-enum class ShouldInterpolate
-{
- eYes,
- eNo
-};
-
-BGRAColor
-HorizontallyInterpolatedPixel(uint32_t aCol,
- uint32_t aWidth,
- const vector<float>& aWeights,
- ShouldInterpolate aShouldInterpolate,
- const vector<BGRAColor>& aColors)
-{
- // We cycle through the vector of weights forever.
- float weight = aWeights[aCol % aWeights.size()];
-
- // Find the columns of the two final pixels for this set of weights.
- uint32_t finalPixel1 = aCol - aCol % aWeights.size();
- uint32_t finalPixel2 = finalPixel1 + aWeights.size();
-
- // If |finalPixel2| is past the end of the row, that means that there is no
- // final pixel after the pixel at |finalPixel1|. In that case, we just want to
- // duplicate |finalPixel1|'s color until the end of the row. We can do that by
- // setting |finalPixel2| equal to |finalPixel1| so that the interpolation has
- // no effect.
- if (finalPixel2 >= aWidth) {
- finalPixel2 = finalPixel1;
- }
-
- // We cycle through the vector of colors forever (subject to the above
- // constraint about the end of the row).
- BGRAColor color1 = aColors[finalPixel1 % aColors.size()];
- BGRAColor color2 = aColors[finalPixel2 % aColors.size()];
-
- // If we're not interpolating, we treat all pixels which aren't final as
- // transparent. Since the number of weights we have is equal to the stride
- // between final pixels, we can check if |aCol| is a final pixel by checking
- // whether |aCol| is a multiple of |aWeights.size()|.
- if (aShouldInterpolate == ShouldInterpolate::eNo) {
- return aCol % aWeights.size() == 0 ? color1
- : BGRAColor::Transparent();
- }
-
- // Interpolate.
- return InterpolateColors(color1, color2, weight);
-}
-
-vector<float>&
-InterpolationWeights(int32_t aStride)
-{
- // Precalculated interpolation weights. These are used to interpolate
- // between final pixels or between important rows. Although no interpolation
- // is actually applied to the previous final pixel or important row value,
- // the arrays still start with 1.0f, which is always skipped, primarily
- // because otherwise |stride1Weights| would have zero elements.
- static vector<float> stride8Weights =
- { 1.0f, 7 / 8.0f, 6 / 8.0f, 5 / 8.0f, 4 / 8.0f, 3 / 8.0f, 2 / 8.0f, 1 / 8.0f };
- static vector<float> stride4Weights = { 1.0f, 3 / 4.0f, 2 / 4.0f, 1 / 4.0f };
- static vector<float> stride2Weights = { 1.0f, 1 / 2.0f };
- static vector<float> stride1Weights = { 1.0f };
-
- switch (aStride) {
- case 8: return stride8Weights;
- case 4: return stride4Weights;
- case 2: return stride2Weights;
- case 1: return stride1Weights;
- default:
- MOZ_CRASH();
- }
-}
-
-int32_t
-ImportantRowStride(uint8_t aPass)
-{
- // The stride between important rows for each pass, with a dummy value for
- // the nonexistent pass 0 and for pass 8, since the tests run an extra pass to
- // make sure nothing breaks.
- static int32_t strides[] = { 1, 8, 8, 4, 4, 2, 2, 1, 1 };
-
- return strides[aPass];
-}
-
-size_t
-FinalPixelStride(uint8_t aPass)
-{
- // The stride between the final pixels in important rows for each pass, with
- // a dummy value for the nonexistent pass 0 and for pass 8, since the tests
- // run an extra pass to make sure nothing breaks.
- static size_t strides[] = { 1, 8, 4, 4, 2, 2, 1, 1, 1 };
-
- return strides[aPass];
-}
-
-bool
-IsImportantRow(int32_t aRow, uint8_t aPass)
-{
- return aRow % ImportantRowStride(aPass) == 0;
-}
-
-/**
- * ADAM7 breaks up the image into 8x8 blocks. On each of the 7 passes, a new
- * set of pixels in each block receives their final values, according to the
- * following pattern:
- *
- * 1 6 4 6 2 6 4 6
- * 7 7 7 7 7 7 7 7
- * 5 6 5 6 5 6 5 6
- * 7 7 7 7 7 7 7 7
- * 3 6 4 6 3 6 4 6
- * 7 7 7 7 7 7 7 7
- * 5 6 5 6 5 6 5 6
- * 7 7 7 7 7 7 7 7
- *
- * This function produces a row of pixels @aWidth wide, suitable for testing
- * horizontal interpolation on pass @aPass. The pattern of pixels used is
- * determined by @aPass and @aRow, which determine which pixels are final
- * according to the table above, and @aColors, from which the pixel values
- * are selected.
- *
- * There are two different behaviors: if |eNo| is passed for
- * @aShouldInterpolate, non-final pixels are treated as transparent. If |eNo|
- * is passed, non-final pixels get interpolated in from the surrounding final
- * pixels. The intention is that |eNo| is passed to generate input which will
- * be run through ADAM7InterpolatingFilter, and |eYes| is passed to generate
- * reference data to check that the filter is performing horizontal
- * interpolation correctly.
- *
- * This function does not perform vertical interpolation. Rows which aren't on
- * the current pass are filled with transparent pixels.
- *
- * @return a vector<BGRAColor> representing a row of pixels.
- */
-vector<BGRAColor>
-ADAM7HorizontallyInterpolatedRow(uint8_t aPass,
- uint32_t aRow,
- uint32_t aWidth,
- ShouldInterpolate aShouldInterpolate,
- const vector<BGRAColor>& aColors)
-{
- EXPECT_GT(aPass, 0);
- EXPECT_LE(aPass, 8);
- EXPECT_GT(aColors.size(), 0u);
-
- vector<BGRAColor> result(aWidth);
-
- if (IsImportantRow(aRow, aPass)) {
- vector<float>& weights = InterpolationWeights(FinalPixelStride(aPass));
-
- // Compute the horizontally interpolated row.
- uint32_t col = 0;
- generate(result.begin(), result.end(), [&]{
- return HorizontallyInterpolatedPixel(col++, aWidth, weights,
- aShouldInterpolate, aColors);
- });
- } else {
- // This is an unimportant row; just make the entire thing transparent.
- generate(result.begin(), result.end(), []{
- return BGRAColor::Transparent();
- });
- }
-
- EXPECT_EQ(result.size(), size_t(aWidth));
-
- return result;
-}
-
-WriteState
-WriteUninterpolatedPixels(SurfaceFilter* aFilter,
- const IntSize& aSize,
- uint8_t aPass,
- const vector<BGRAColor>& aColors)
-{
- WriteState result = WriteState::NEED_MORE_DATA;
-
- for (int32_t row = 0; row < aSize.height; ++row) {
- // Compute uninterpolated pixels for this row.
- vector<BGRAColor> pixels =
- Move(ADAM7HorizontallyInterpolatedRow(aPass, row, aSize.width,
- ShouldInterpolate::eNo, aColors));
-
- // Write them to the surface.
- auto pixelIterator = pixels.cbegin();
- result = aFilter->WritePixelsToRow<uint32_t>([&]{
- return AsVariant((*pixelIterator++).AsPixel());
- });
-
- if (result != WriteState::NEED_MORE_DATA) {
- break;
- }
- }
-
- return result;
-}
-
-bool
-CheckHorizontallyInterpolatedImage(Decoder* aDecoder,
- const IntSize& aSize,
- uint8_t aPass,
- const vector<BGRAColor>& aColors)
-{
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- for (int32_t row = 0; row < aSize.height; ++row) {
- if (!IsImportantRow(row, aPass)) {
- continue; // Don't check rows which aren't important on this pass.
- }
-
- // Compute the expected pixels, *with* interpolation to match what the
- // filter should have done.
- vector<BGRAColor> expectedPixels =
- Move(ADAM7HorizontallyInterpolatedRow(aPass, row, aSize.width,
- ShouldInterpolate::eYes, aColors));
-
- if (!RowHasPixels(surface, row, expectedPixels)) {
- return false;
- }
- }
-
- return true;
-}
-
-void
-CheckHorizontalInterpolation(const IntSize& aSize,
- const vector<BGRAColor>& aColors)
-{
- const IntRect surfaceRect(IntPoint(0, 0), aSize);
-
- WithADAM7InterpolatingFilter(aSize,
- [&](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // We check horizontal interpolation behavior for each pass individually. In
- // addition to the normal 7 passes that ADAM7 includes, we also check an
- // eighth pass to verify that nothing breaks if extra data is written.
- for (uint8_t pass = 1; pass <= 8; ++pass) {
- // Write our color pattern to the surface. We don't perform any
- // interpolation when writing to the filter so that we can check that the
- // filter itself *does*.
- WriteState result =
- WriteUninterpolatedPixels(aFilter, aSize, pass, aColors);
-
- EXPECT_EQ(WriteState::FINISHED, result);
- AssertCorrectPipelineFinalState(aFilter, surfaceRect, surfaceRect);
-
- // Check that the generated image matches the expected pattern, with
- // interpolation applied.
- EXPECT_TRUE(CheckHorizontallyInterpolatedImage(aDecoder, aSize,
- pass, aColors));
-
- // Prepare for the next pass.
- aFilter->ResetToFirstRow();
- }
- });
-}
-
-BGRAColor
-ADAM7RowColor(int32_t aRow,
- uint8_t aPass,
- const vector<BGRAColor>& aColors)
-{
- EXPECT_LT(0, aPass);
- EXPECT_GE(8, aPass);
- EXPECT_LT(0u, aColors.size());
-
- // If this is an important row, select the color from the provided vector of
- // colors, which we cycle through infinitely. If not, just fill the row with
- // transparent pixels.
- return IsImportantRow(aRow, aPass) ? aColors[aRow % aColors.size()]
- : BGRAColor::Transparent();
-}
-
-WriteState
-WriteRowColorPixels(SurfaceFilter* aFilter,
- const IntSize& aSize,
- uint8_t aPass,
- const vector<BGRAColor>& aColors)
-{
- WriteState result = WriteState::NEED_MORE_DATA;
-
- for (int32_t row = 0; row < aSize.height; ++row) {
- const uint32_t color = ADAM7RowColor(row, aPass, aColors).AsPixel();
-
- // Fill the surface with |color| pixels.
- result = aFilter->WritePixelsToRow<uint32_t>([&]{ return AsVariant(color); });
-
- if (result != WriteState::NEED_MORE_DATA) {
- break;
- }
- }
-
- return result;
-}
-
-bool
-CheckVerticallyInterpolatedImage(Decoder* aDecoder,
- const IntSize& aSize,
- uint8_t aPass,
- const vector<BGRAColor>& aColors)
-{
- vector<float>& weights = InterpolationWeights(ImportantRowStride(aPass));
-
- for (int32_t row = 0; row < aSize.height; ++row) {
- // Vertically interpolation takes place between two important rows. The
- // separation between the important rows is determined by the stride of this
- // pass. When there is no "next" important row because we'd run off the
- // bottom of the image, we use the same row for both. This matches
- // ADAM7InterpolatingFilter's behavior of duplicating the last important row
- // since there isn't another important row to vertically interpolate it
- // with.
- const int32_t stride = ImportantRowStride(aPass);
- const int32_t prevImportantRow = row - row % stride;
- const int32_t maybeNextImportantRow = prevImportantRow + stride;
- const int32_t nextImportantRow = maybeNextImportantRow < aSize.height
- ? maybeNextImportantRow
- : prevImportantRow;
-
- // Retrieve the colors for the important rows we're going to interpolate.
- const BGRAColor prevImportantRowColor =
- ADAM7RowColor(prevImportantRow, aPass, aColors);
- const BGRAColor nextImportantRowColor =
- ADAM7RowColor(nextImportantRow, aPass, aColors);
-
- // The weight we'll use for interpolation is also determined by the stride.
- // A row halfway between two important rows should have pixels that have a
- // 50% contribution from each of the important rows, for example.
- const float weight = weights[row % stride];
- const BGRAColor interpolatedColor =
- InterpolateColors(prevImportantRowColor, nextImportantRowColor, weight);
-
- // Generate a row of expected pixels. Every pixel in the row is always the
- // same color since we're only testing vertical interpolation between
- // solid-colored rows.
- vector<BGRAColor> expectedPixels(aSize.width);
- generate(expectedPixels.begin(), expectedPixels.end(), [&]{
- return interpolatedColor;
- });
-
- // Check that the pixels match.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- if (!RowHasPixels(surface, row, expectedPixels)) {
- return false;
- }
- }
-
- return true;
-}
-
-void
-CheckVerticalInterpolation(const IntSize& aSize,
- const vector<BGRAColor>& aColors)
-{
- const IntRect surfaceRect(IntPoint(0, 0), aSize);
-
- WithADAM7InterpolatingFilter(aSize,
- [&](Decoder* aDecoder, SurfaceFilter* aFilter) {
- for (uint8_t pass = 1; pass <= 8; ++pass) {
- // Write a pattern of rows to the surface. Important rows will receive a
- // color selected from |aColors|; unimportant rows will be transparent.
- WriteState result = WriteRowColorPixels(aFilter, aSize, pass, aColors);
-
- EXPECT_EQ(WriteState::FINISHED, result);
- AssertCorrectPipelineFinalState(aFilter, surfaceRect, surfaceRect);
-
- // Check that the generated image matches the expected pattern, with
- // interpolation applied.
- EXPECT_TRUE(CheckVerticallyInterpolatedImage(aDecoder, aSize,
- pass, aColors));
-
- // Prepare for the next pass.
- aFilter->ResetToFirstRow();
- }
- });
-}
-
-void
-CheckInterpolation(const IntSize& aSize, const vector<BGRAColor>& aColors)
-{
- CheckHorizontalInterpolation(aSize, aColors);
- CheckVerticalInterpolation(aSize, aColors);
-}
-
-void
-CheckADAM7InterpolatingWritePixels(const IntSize& aSize)
-{
- // This test writes 8 passes of green pixels (the seven ADAM7 passes, plus one
- // extra to make sure nothing goes wrong if we write too much input) and verifies
- // that the output is a solid green surface each time. Because all the pixels
- // are the same color, interpolation doesn't matter; we test the correctness
- // of the interpolation algorithm itself separately.
- WithADAM7InterpolatingFilter(aSize,
- [&](Decoder* aDecoder, SurfaceFilter* aFilter) {
- IntRect rect(IntPoint(0, 0), aSize);
-
- for (int32_t pass = 1; pass <= 8; ++pass) {
- // We only actually write up to the last important row for each pass,
- // because that row unambiguously determines the remaining rows.
- const int32_t lastRow = aSize.height - 1;
- const int32_t lastImportantRow =
- lastRow - (lastRow % ImportantRowStride(pass));
- const IntRect inputWriteRect(0, 0, aSize.width, lastImportantRow + 1);
-
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(rect),
- /* aInputRect = */ Some(rect),
- /* aInputWriteRect = */ Some(inputWriteRect));
-
- aFilter->ResetToFirstRow();
- EXPECT_FALSE(aFilter->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
- }
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels100_100)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(100, 100));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels99_99)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(99, 99));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels66_33)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(66, 33));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels33_66)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(33, 66));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels15_15)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(15, 15));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels9_9)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(9, 9));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels8_8)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(8, 8));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels7_7)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(7, 7));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels3_3)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(3, 3));
-}
-
-TEST(ImageADAM7InterpolatingFilter, WritePixels1_1)
-{
- CheckADAM7InterpolatingWritePixels(IntSize(1, 1));
-}
-
-TEST(ImageADAM7InterpolatingFilter, TrivialInterpolation48_48)
-{
- CheckInterpolation(IntSize(48, 48), { BGRAColor::Green() });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput33_17)
-{
- // We check interpolation using irregular patterns to make sure that the
- // interpolation will look different for different passes.
- CheckInterpolation(IntSize(33, 17), {
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
- BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
- BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput32_16)
-{
- CheckInterpolation(IntSize(32, 16), {
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
- BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
- BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput31_15)
-{
- CheckInterpolation(IntSize(31, 15), {
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Blue(),
- BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue(),
- BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput17_33)
-{
- CheckInterpolation(IntSize(17, 33), {
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
- BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput16_32)
-{
- CheckInterpolation(IntSize(16, 32), {
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
- BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput15_31)
-{
- CheckInterpolation(IntSize(15, 31), {
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(),
- BGRAColor::Red(), BGRAColor::Green(), BGRAColor::Blue(), BGRAColor::Red(),
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput9_9)
-{
- CheckInterpolation(IntSize(9, 9), {
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput8_8)
-{
- CheckInterpolation(IntSize(8, 8), {
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput7_7)
-{
- CheckInterpolation(IntSize(7, 7), {
- BGRAColor::Blue(), BGRAColor::Blue(), BGRAColor::Red(), BGRAColor::Green(),
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Red(), BGRAColor::Blue()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput3_3)
-{
- CheckInterpolation(IntSize(3, 3), {
- BGRAColor::Green(), BGRAColor::Red(), BGRAColor::Blue(), BGRAColor::Red()
- });
-}
-
-TEST(ImageADAM7InterpolatingFilter, InterpolationOutput1_1)
-{
- CheckInterpolation(IntSize(1, 1), { BGRAColor::Blue() });
-}
-
-TEST(ImageADAM7InterpolatingFilter, ADAM7InterpolationFailsFor0_0)
-{
- // A 0x0 input size is invalid, so configuration should fail.
- AssertConfiguringADAM7InterpolatingFilterFails(IntSize(0, 0));
-}
-
-TEST(ImageADAM7InterpolatingFilter, ADAM7InterpolationFailsForMinus1_Minus1)
-{
- // A negative input size is invalid, so configuration should fail.
- AssertConfiguringADAM7InterpolatingFilterFails(IntSize(-1, -1));
-}
-
-TEST(ImageADAM7InterpolatingFilter, ConfiguringPalettedADAM7InterpolatingFilterFails)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- // ADAM7InterpolatingFilter does not support paletted images, so configuration
- // should fail.
- AssertConfiguringPipelineFails(decoder,
- ADAM7InterpolatingConfig { },
- PalettedSurfaceConfig { decoder, IntSize(100, 100),
- IntRect(0, 0, 50, 50),
- SurfaceFormat::B8G8R8A8, 8,
- false });
-}
diff --git a/image/test/gtest/TestCopyOnWrite.cpp b/image/test/gtest/TestCopyOnWrite.cpp
deleted file mode 100644
index 0d420b672..000000000
--- a/image/test/gtest/TestCopyOnWrite.cpp
+++ /dev/null
@@ -1,235 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "CopyOnWrite.h"
-
-using namespace mozilla;
-using namespace mozilla::image;
-
-struct ValueStats
-{
- int32_t mCopies = 0;
- int32_t mFrees = 0;
- int32_t mCalls = 0;
- int32_t mConstCalls = 0;
- int32_t mSerial = 0;
-};
-
-struct Value
-{
- NS_INLINE_DECL_REFCOUNTING(Value)
-
- explicit Value(ValueStats& aStats)
- : mStats(aStats)
- , mSerial(mStats.mSerial++)
- { }
-
- Value(const Value& aOther)
- : mStats(aOther.mStats)
- , mSerial(mStats.mSerial++)
- {
- mStats.mCopies++;
- }
-
- void Go() { mStats.mCalls++; }
- void Go() const { mStats.mConstCalls++; }
-
- int32_t Serial() const { return mSerial; }
-
-protected:
- ~Value() { mStats.mFrees++; }
-
-private:
- ValueStats& mStats;
- int32_t mSerial;
-};
-
-TEST(ImageCopyOnWrite, Read)
-{
- ValueStats stats;
-
- {
- CopyOnWrite<Value> cow(new Value(stats));
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_TRUE(cow.CanRead());
-
- cow.Read([&](const Value* aValue) {
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(0, aValue->Serial());
- EXPECT_TRUE(cow.CanRead());
- EXPECT_TRUE(cow.CanWrite());
-
- aValue->Go();
-
- EXPECT_EQ(0, stats.mCalls);
- EXPECT_EQ(1, stats.mConstCalls);
- });
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(0, stats.mCalls);
- EXPECT_EQ(1, stats.mConstCalls);
- }
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(1, stats.mFrees);
-}
-
-TEST(ImageCopyOnWrite, RecursiveRead)
-{
- ValueStats stats;
-
- {
- CopyOnWrite<Value> cow(new Value(stats));
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_TRUE(cow.CanRead());
-
- cow.Read([&](const Value* aValue) {
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(0, aValue->Serial());
- EXPECT_TRUE(cow.CanRead());
- EXPECT_TRUE(cow.CanWrite());
-
- // Make sure that Read() inside a Read() succeeds.
- cow.Read([&](const Value* aValue) {
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(0, aValue->Serial());
- EXPECT_TRUE(cow.CanRead());
- EXPECT_TRUE(cow.CanWrite());
-
- aValue->Go();
-
- EXPECT_EQ(0, stats.mCalls);
- EXPECT_EQ(1, stats.mConstCalls);
- }, []() {
- // This gets called if we can't read. We shouldn't get here.
- EXPECT_TRUE(false);
- });
- });
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(0, stats.mCalls);
- EXPECT_EQ(1, stats.mConstCalls);
- }
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(1, stats.mFrees);
-}
-
-TEST(ImageCopyOnWrite, Write)
-{
- ValueStats stats;
-
- {
- CopyOnWrite<Value> cow(new Value(stats));
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_TRUE(cow.CanRead());
- EXPECT_TRUE(cow.CanWrite());
-
- cow.Write([&](Value* aValue) {
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(0, aValue->Serial());
- EXPECT_TRUE(!cow.CanRead());
- EXPECT_TRUE(!cow.CanWrite());
-
- aValue->Go();
-
- EXPECT_EQ(1, stats.mCalls);
- EXPECT_EQ(0, stats.mConstCalls);
- });
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(1, stats.mCalls);
- EXPECT_EQ(0, stats.mConstCalls);
- }
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(1, stats.mFrees);
-}
-
-TEST(ImageCopyOnWrite, WriteRecursive)
-{
- ValueStats stats;
-
- {
- CopyOnWrite<Value> cow(new Value(stats));
-
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_TRUE(cow.CanRead());
- EXPECT_TRUE(cow.CanWrite());
-
- cow.Read([&](const Value* aValue) {
- EXPECT_EQ(0, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(0, aValue->Serial());
- EXPECT_TRUE(cow.CanRead());
- EXPECT_TRUE(cow.CanWrite());
-
- // Make sure Write() inside a Read() succeeds.
- cow.Write([&](Value* aValue) {
- EXPECT_EQ(1, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(1, aValue->Serial());
- EXPECT_TRUE(!cow.CanRead());
- EXPECT_TRUE(!cow.CanWrite());
-
- aValue->Go();
-
- EXPECT_EQ(1, stats.mCalls);
- EXPECT_EQ(0, stats.mConstCalls);
-
- // Make sure Read() inside a Write() fails.
- cow.Read([](const Value* aValue) {
- // This gets called if we can read. We shouldn't get here.
- EXPECT_TRUE(false);
- }, []() {
- // This gets called if we can't read. We *should* get here.
- EXPECT_TRUE(true);
- });
-
- // Make sure Write() inside a Write() fails.
- cow.Write([](Value* aValue) {
- // This gets called if we can write. We shouldn't get here.
- EXPECT_TRUE(false);
- }, []() {
- // This gets called if we can't write. We *should* get here.
- EXPECT_TRUE(true);
- });
- }, []() {
- // This gets called if we can't write. We shouldn't get here.
- EXPECT_TRUE(false);
- });
-
- aValue->Go();
-
- EXPECT_EQ(1, stats.mCopies);
- EXPECT_EQ(0, stats.mFrees);
- EXPECT_EQ(1, stats.mCalls);
- EXPECT_EQ(1, stats.mConstCalls);
- });
-
- EXPECT_EQ(1, stats.mCopies);
- EXPECT_EQ(1, stats.mFrees);
- EXPECT_EQ(1, stats.mCalls);
- EXPECT_EQ(1, stats.mConstCalls);
- }
-
- EXPECT_EQ(1, stats.mCopies);
- EXPECT_EQ(2, stats.mFrees);
-}
diff --git a/image/test/gtest/TestDecodeToSurface.cpp b/image/test/gtest/TestDecodeToSurface.cpp
deleted file mode 100644
index bd52e7590..000000000
--- a/image/test/gtest/TestDecodeToSurface.cpp
+++ /dev/null
@@ -1,123 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "Common.h"
-#include "imgIContainer.h"
-#include "imgITools.h"
-#include "ImageOps.h"
-#include "mozilla/gfx/2D.h"
-#include "nsComponentManagerUtils.h"
-#include "nsCOMPtr.h"
-#include "nsIInputStream.h"
-#include "nsIRunnable.h"
-#include "nsIThread.h"
-#include "mozilla/RefPtr.h"
-#include "nsString.h"
-#include "nsThreadUtils.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-class DecodeToSurfaceRunnable : public Runnable
-{
-public:
- DecodeToSurfaceRunnable(RefPtr<SourceSurface>& aSurface,
- nsIInputStream* aInputStream,
- const ImageTestCase& aTestCase)
- : mSurface(aSurface)
- , mInputStream(aInputStream)
- , mTestCase(aTestCase)
- { }
-
- NS_IMETHOD Run() override
- {
- Go();
- return NS_OK;
- }
-
- void Go()
- {
- mSurface =
- ImageOps::DecodeToSurface(mInputStream,
- nsDependentCString(mTestCase.mMimeType),
- imgIContainer::DECODE_FLAGS_DEFAULT);
- ASSERT_TRUE(mSurface != nullptr);
-
- EXPECT_EQ(SurfaceType::DATA, mSurface->GetType());
- EXPECT_TRUE(mSurface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
- mSurface->GetFormat() == SurfaceFormat::B8G8R8A8);
- EXPECT_EQ(mTestCase.mSize, mSurface->GetSize());
-
- EXPECT_TRUE(IsSolidColor(mSurface, BGRAColor::Green(),
- mTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0));
- }
-
-private:
- RefPtr<SourceSurface>& mSurface;
- nsCOMPtr<nsIInputStream> mInputStream;
- ImageTestCase mTestCase;
-};
-
-static void
-RunDecodeToSurface(const ImageTestCase& aTestCase)
-{
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
- ASSERT_TRUE(inputStream != nullptr);
-
- nsCOMPtr<nsIThread> thread;
- nsresult rv = NS_NewThread(getter_AddRefs(thread), nullptr);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // We run the DecodeToSurface tests off-main-thread to ensure that
- // DecodeToSurface doesn't require any main-thread-only code.
- RefPtr<SourceSurface> surface;
- nsCOMPtr<nsIRunnable> runnable =
- new DecodeToSurfaceRunnable(surface, inputStream, aTestCase);
- thread->Dispatch(runnable, nsIThread::DISPATCH_SYNC);
-
- thread->Shutdown();
-
- // Explicitly release the SourceSurface on the main thread.
- surface = nullptr;
-}
-
-class ImageDecodeToSurface : public ::testing::Test
-{
-protected:
- AutoInitializeImageLib mInit;
-};
-
-TEST_F(ImageDecodeToSurface, PNG) { RunDecodeToSurface(GreenPNGTestCase()); }
-TEST_F(ImageDecodeToSurface, GIF) { RunDecodeToSurface(GreenGIFTestCase()); }
-TEST_F(ImageDecodeToSurface, JPG) { RunDecodeToSurface(GreenJPGTestCase()); }
-TEST_F(ImageDecodeToSurface, BMP) { RunDecodeToSurface(GreenBMPTestCase()); }
-TEST_F(ImageDecodeToSurface, ICO) { RunDecodeToSurface(GreenICOTestCase()); }
-TEST_F(ImageDecodeToSurface, Icon) { RunDecodeToSurface(GreenIconTestCase()); }
-
-TEST_F(ImageDecodeToSurface, AnimatedGIF)
-{
- RunDecodeToSurface(GreenFirstFrameAnimatedGIFTestCase());
-}
-
-TEST_F(ImageDecodeToSurface, AnimatedPNG)
-{
- RunDecodeToSurface(GreenFirstFrameAnimatedPNGTestCase());
-}
-
-TEST_F(ImageDecodeToSurface, Corrupt)
-{
- ImageTestCase testCase = CorruptTestCase();
-
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
- ASSERT_TRUE(inputStream != nullptr);
-
- RefPtr<SourceSurface> surface =
- ImageOps::DecodeToSurface(inputStream,
- nsDependentCString(testCase.mMimeType),
- imgIContainer::DECODE_FLAGS_DEFAULT);
- EXPECT_TRUE(surface == nullptr);
-}
diff --git a/image/test/gtest/TestDecoders.cpp b/image/test/gtest/TestDecoders.cpp
deleted file mode 100644
index 58caa77a2..000000000
--- a/image/test/gtest/TestDecoders.cpp
+++ /dev/null
@@ -1,669 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "Common.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "decoders/nsBMPDecoder.h"
-#include "IDecodingTask.h"
-#include "imgIContainer.h"
-#include "imgITools.h"
-#include "ImageFactory.h"
-#include "mozilla/gfx/2D.h"
-#include "nsComponentManagerUtils.h"
-#include "nsCOMPtr.h"
-#include "nsIInputStream.h"
-#include "nsIRunnable.h"
-#include "nsIThread.h"
-#include "mozilla/RefPtr.h"
-#include "nsStreamUtils.h"
-#include "nsString.h"
-#include "nsThreadUtils.h"
-#include "ProgressTracker.h"
-#include "SourceBuffer.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-static already_AddRefed<SourceSurface>
-CheckDecoderState(const ImageTestCase& aTestCase, Decoder* aDecoder)
-{
- EXPECT_TRUE(aDecoder->GetDecodeDone());
- EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR),
- aDecoder->HasError());
-
- // Verify that the decoder made the expected progress.
- Progress progress = aDecoder->TakeProgress();
- EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR),
- bool(progress & FLAG_HAS_ERROR));
-
- if (aTestCase.mFlags & TEST_CASE_HAS_ERROR) {
- return nullptr; // That's all we can check for bad images.
- }
-
- EXPECT_TRUE(bool(progress & FLAG_SIZE_AVAILABLE));
- EXPECT_TRUE(bool(progress & FLAG_DECODE_COMPLETE));
- EXPECT_TRUE(bool(progress & FLAG_FRAME_COMPLETE));
- EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_TRANSPARENT),
- bool(progress & FLAG_HAS_TRANSPARENCY));
- EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_ANIMATED),
- bool(progress & FLAG_IS_ANIMATED));
-
- // The decoder should get the correct size.
- IntSize size = aDecoder->Size();
- EXPECT_EQ(aTestCase.mSize.width, size.width);
- EXPECT_EQ(aTestCase.mSize.height, size.height);
-
- // Get the current frame, which is always the first frame of the image
- // because CreateAnonymousDecoder() forces a first-frame-only decode.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- // Verify that the resulting surfaces matches our expectations.
- EXPECT_EQ(SurfaceType::DATA, surface->GetType());
- EXPECT_TRUE(surface->GetFormat() == SurfaceFormat::B8G8R8X8 ||
- surface->GetFormat() == SurfaceFormat::B8G8R8A8);
- EXPECT_EQ(aTestCase.mOutputSize, surface->GetSize());
-
- return surface.forget();
-}
-
-static void
-CheckDecoderResults(const ImageTestCase& aTestCase, Decoder* aDecoder)
-{
- RefPtr<SourceSurface> surface = CheckDecoderState(aTestCase, aDecoder);
- if (!surface) {
- return;
- }
-
- if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
- return;
- }
-
- // Check the output.
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green(),
- aTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0));
-}
-
-template <typename Func>
-void WithSingleChunkDecode(const ImageTestCase& aTestCase,
- const Maybe<IntSize>& aOutputSize,
- Func aResultChecker)
-{
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
- ASSERT_TRUE(inputStream != nullptr);
-
- // Figure out how much data we have.
- uint64_t length;
- nsresult rv = inputStream->Available(&length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Write the data into a SourceBuffer.
- NotNull<RefPtr<SourceBuffer>> sourceBuffer = WrapNotNull(new SourceBuffer());
- sourceBuffer->ExpectLength(length);
- rv = sourceBuffer->AppendFromInputStream(inputStream, length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
- sourceBuffer->Complete(NS_OK);
-
- // Create a decoder.
- DecoderType decoderType =
- DecoderFactory::GetDecoderType(aTestCase.mMimeType);
- RefPtr<Decoder> decoder =
- DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, aOutputSize,
- DefaultSurfaceFlags());
- ASSERT_TRUE(decoder != nullptr);
- RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
-
- // Run the full decoder synchronously.
- task->Run();
-
- // Call the lambda to verify the expected results.
- aResultChecker(decoder);
-}
-
-static void
-CheckDecoderSingleChunk(const ImageTestCase& aTestCase)
-{
- WithSingleChunkDecode(aTestCase, Nothing(), [&](Decoder* aDecoder) {
- CheckDecoderResults(aTestCase, aDecoder);
- });
-}
-
-static void
-CheckDecoderMultiChunk(const ImageTestCase& aTestCase)
-{
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
- ASSERT_TRUE(inputStream != nullptr);
-
- // Figure out how much data we have.
- uint64_t length;
- nsresult rv = inputStream->Available(&length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Create a SourceBuffer and a decoder.
- NotNull<RefPtr<SourceBuffer>> sourceBuffer = WrapNotNull(new SourceBuffer());
- sourceBuffer->ExpectLength(length);
- DecoderType decoderType =
- DecoderFactory::GetDecoderType(aTestCase.mMimeType);
- RefPtr<Decoder> decoder =
- DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(),
- DefaultSurfaceFlags());
- ASSERT_TRUE(decoder != nullptr);
- RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
-
- for (uint64_t read = 0; read < length ; ++read) {
- uint64_t available = 0;
- rv = inputStream->Available(&available);
- ASSERT_TRUE(available > 0);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- rv = sourceBuffer->AppendFromInputStream(inputStream, 1);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- task->Run();
- }
-
- sourceBuffer->Complete(NS_OK);
- task->Run();
-
- CheckDecoderResults(aTestCase, decoder);
-}
-
-static void
-CheckDownscaleDuringDecode(const ImageTestCase& aTestCase)
-{
- // This function expects that |aTestCase| consists of 25 lines of green,
- // followed by 25 lines of red, followed by 25 lines of green, followed by 25
- // more lines of red. We'll downscale it from 100x100 to 20x20.
- IntSize outputSize(20, 20);
-
- WithSingleChunkDecode(aTestCase, Some(outputSize), [&](Decoder* aDecoder) {
- RefPtr<SourceSurface> surface = CheckDecoderState(aTestCase, aDecoder);
-
- // There are no downscale-during-decode tests that have TEST_CASE_HAS_ERROR
- // set, so we expect to always get a surface here.
- EXPECT_TRUE(surface != nullptr);
-
- if (aTestCase.mFlags & TEST_CASE_IGNORE_OUTPUT) {
- return;
- }
-
- // Check that the downscaled image is correct. Note that we skip rows near
- // the transitions between colors, since the downscaler does not produce a
- // sharp boundary at these points. Even some of the rows we test need a
- // small amount of fuzz; this is just the nature of Lanczos downscaling.
- EXPECT_TRUE(RowsAreSolidColor(surface, 0, 4, BGRAColor::Green(), /* aFuzz = */ 47));
- EXPECT_TRUE(RowsAreSolidColor(surface, 6, 3, BGRAColor::Red(), /* aFuzz = */ 27));
- EXPECT_TRUE(RowsAreSolidColor(surface, 11, 3, BGRAColor::Green(), /* aFuzz = */ 47));
- EXPECT_TRUE(RowsAreSolidColor(surface, 16, 4, BGRAColor::Red(), /* aFuzz = */ 27));
- });
-}
-
-class ImageDecoders : public ::testing::Test
-{
-protected:
- AutoInitializeImageLib mInit;
-};
-
-TEST_F(ImageDecoders, PNGSingleChunk)
-{
- CheckDecoderSingleChunk(GreenPNGTestCase());
-}
-
-TEST_F(ImageDecoders, PNGMultiChunk)
-{
- CheckDecoderMultiChunk(GreenPNGTestCase());
-}
-
-TEST_F(ImageDecoders, PNGDownscaleDuringDecode)
-{
- CheckDownscaleDuringDecode(DownscaledPNGTestCase());
-}
-
-TEST_F(ImageDecoders, GIFSingleChunk)
-{
- CheckDecoderSingleChunk(GreenGIFTestCase());
-}
-
-TEST_F(ImageDecoders, GIFMultiChunk)
-{
- CheckDecoderMultiChunk(GreenGIFTestCase());
-}
-
-TEST_F(ImageDecoders, GIFDownscaleDuringDecode)
-{
- CheckDownscaleDuringDecode(DownscaledGIFTestCase());
-}
-
-TEST_F(ImageDecoders, JPGSingleChunk)
-{
- CheckDecoderSingleChunk(GreenJPGTestCase());
-}
-
-TEST_F(ImageDecoders, JPGMultiChunk)
-{
- CheckDecoderMultiChunk(GreenJPGTestCase());
-}
-
-TEST_F(ImageDecoders, JPGDownscaleDuringDecode)
-{
- CheckDownscaleDuringDecode(DownscaledJPGTestCase());
-}
-
-TEST_F(ImageDecoders, BMPSingleChunk)
-{
- CheckDecoderSingleChunk(GreenBMPTestCase());
-}
-
-TEST_F(ImageDecoders, BMPMultiChunk)
-{
- CheckDecoderMultiChunk(GreenBMPTestCase());
-}
-
-TEST_F(ImageDecoders, BMPDownscaleDuringDecode)
-{
- CheckDownscaleDuringDecode(DownscaledBMPTestCase());
-}
-
-TEST_F(ImageDecoders, ICOSingleChunk)
-{
- CheckDecoderSingleChunk(GreenICOTestCase());
-}
-
-TEST_F(ImageDecoders, ICOMultiChunk)
-{
- CheckDecoderMultiChunk(GreenICOTestCase());
-}
-
-TEST_F(ImageDecoders, ICODownscaleDuringDecode)
-{
- CheckDownscaleDuringDecode(DownscaledICOTestCase());
-}
-
-TEST_F(ImageDecoders, ICOWithANDMaskDownscaleDuringDecode)
-{
- CheckDownscaleDuringDecode(DownscaledTransparentICOWithANDMaskTestCase());
-}
-
-TEST_F(ImageDecoders, IconSingleChunk)
-{
- CheckDecoderSingleChunk(GreenIconTestCase());
-}
-
-TEST_F(ImageDecoders, IconMultiChunk)
-{
- CheckDecoderMultiChunk(GreenIconTestCase());
-}
-
-TEST_F(ImageDecoders, IconDownscaleDuringDecode)
-{
- CheckDownscaleDuringDecode(DownscaledIconTestCase());
-}
-
-TEST_F(ImageDecoders, AnimatedGIFSingleChunk)
-{
- CheckDecoderSingleChunk(GreenFirstFrameAnimatedGIFTestCase());
-}
-
-TEST_F(ImageDecoders, AnimatedGIFMultiChunk)
-{
- CheckDecoderMultiChunk(GreenFirstFrameAnimatedGIFTestCase());
-}
-
-TEST_F(ImageDecoders, AnimatedPNGSingleChunk)
-{
- CheckDecoderSingleChunk(GreenFirstFrameAnimatedPNGTestCase());
-}
-
-TEST_F(ImageDecoders, AnimatedPNGMultiChunk)
-{
- CheckDecoderMultiChunk(GreenFirstFrameAnimatedPNGTestCase());
-}
-
-TEST_F(ImageDecoders, CorruptSingleChunk)
-{
- CheckDecoderSingleChunk(CorruptTestCase());
-}
-
-TEST_F(ImageDecoders, CorruptMultiChunk)
-{
- CheckDecoderMultiChunk(CorruptTestCase());
-}
-
-TEST_F(ImageDecoders, CorruptBMPWithTruncatedHeaderSingleChunk)
-{
- CheckDecoderSingleChunk(CorruptBMPWithTruncatedHeader());
-}
-
-TEST_F(ImageDecoders, CorruptBMPWithTruncatedHeaderMultiChunk)
-{
- CheckDecoderMultiChunk(CorruptBMPWithTruncatedHeader());
-}
-
-TEST_F(ImageDecoders, CorruptICOWithBadBMPWidthSingleChunk)
-{
- CheckDecoderSingleChunk(CorruptICOWithBadBMPWidthTestCase());
-}
-
-TEST_F(ImageDecoders, CorruptICOWithBadBMPWidthMultiChunk)
-{
- CheckDecoderMultiChunk(CorruptICOWithBadBMPWidthTestCase());
-}
-
-TEST_F(ImageDecoders, CorruptICOWithBadBMPHeightSingleChunk)
-{
- CheckDecoderSingleChunk(CorruptICOWithBadBMPHeightTestCase());
-}
-
-TEST_F(ImageDecoders, CorruptICOWithBadBMPHeightMultiChunk)
-{
- CheckDecoderMultiChunk(CorruptICOWithBadBMPHeightTestCase());
-}
-
-TEST_F(ImageDecoders, AnimatedGIFWithFRAME_FIRST)
-{
- ImageTestCase testCase = GreenFirstFrameAnimatedGIFTestCase();
-
- // Verify that we can decode this test case and retrieve the first frame using
- // imgIContainer::FRAME_FIRST. This ensures that we correctly trigger a
- // single-frame decode rather than an animated decode when
- // imgIContainer::FRAME_FIRST is requested.
-
- // Create an image.
- RefPtr<Image> image =
- ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
- ASSERT_TRUE(!image->HasError());
-
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
- ASSERT_TRUE(inputStream);
-
- // Figure out how much data we have.
- uint64_t length;
- nsresult rv = inputStream->Available(&length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Write the data into the image.
- rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
- static_cast<uint32_t>(length));
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Let the image know we've sent all the data.
- rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
- tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
-
- // Lock the image so its surfaces don't disappear during the test.
- image->LockImage();
-
- // Use GetFrame() to force a sync decode of the image, specifying FRAME_FIRST
- // to ensure that we don't get an animated decode.
- RefPtr<SourceSurface> surface =
- image->GetFrame(imgIContainer::FRAME_FIRST,
- imgIContainer::FLAG_SYNC_DECODE);
-
- // Ensure that the image's metadata meets our expectations.
- IntSize imageSize(0, 0);
- rv = image->GetWidth(&imageSize.width);
- EXPECT_TRUE(NS_SUCCEEDED(rv));
- rv = image->GetHeight(&imageSize.height);
- EXPECT_TRUE(NS_SUCCEEDED(rv));
-
- EXPECT_EQ(testCase.mSize.width, imageSize.width);
- EXPECT_EQ(testCase.mSize.height, imageSize.height);
-
- Progress imageProgress = tracker->GetProgress();
-
- EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
- EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);
-
- // Ensure that we decoded the static version of the image.
- {
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eStatic));
- ASSERT_EQ(MatchType::EXACT, result.Type());
- EXPECT_TRUE(bool(result.Surface()));
- }
-
- // Ensure that we didn't decode the animated version of the image.
- {
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eAnimated));
- ASSERT_EQ(MatchType::NOT_FOUND, result.Type());
- }
-
- // Use GetFrame() to force a sync decode of the image, this time specifying
- // FRAME_CURRENT to ensure that we get an animated decode.
- RefPtr<SourceSurface> animatedSurface =
- image->GetFrame(imgIContainer::FRAME_CURRENT,
- imgIContainer::FLAG_SYNC_DECODE);
-
- // Ensure that we decoded both frames of the animated version of the image.
- {
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eAnimated));
- ASSERT_EQ(MatchType::EXACT, result.Type());
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
- EXPECT_TRUE(bool(result.Surface()));
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(1)));
- EXPECT_TRUE(bool(result.Surface()));
- }
-
- // Ensure that the static version is still around.
- {
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eStatic));
- ASSERT_EQ(MatchType::EXACT, result.Type());
- EXPECT_TRUE(bool(result.Surface()));
- }
-}
-
-TEST_F(ImageDecoders, AnimatedGIFWithFRAME_CURRENT)
-{
- ImageTestCase testCase = GreenFirstFrameAnimatedGIFTestCase();
-
- // Verify that we can decode this test case and retrieve the entire sequence
- // of frames using imgIContainer::FRAME_CURRENT. This ensures that we
- // correctly trigger an animated decode rather than a single-frame decode when
- // imgIContainer::FRAME_CURRENT is requested.
-
- // Create an image.
- RefPtr<Image> image =
- ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
- ASSERT_TRUE(!image->HasError());
-
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
- ASSERT_TRUE(inputStream);
-
- // Figure out how much data we have.
- uint64_t length;
- nsresult rv = inputStream->Available(&length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Write the data into the image.
- rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
- static_cast<uint32_t>(length));
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Let the image know we've sent all the data.
- rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
- tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
-
- // Lock the image so its surfaces don't disappear during the test.
- image->LockImage();
-
- // Use GetFrame() to force a sync decode of the image, specifying
- // FRAME_CURRENT to ensure we get an animated decode.
- RefPtr<SourceSurface> surface =
- image->GetFrame(imgIContainer::FRAME_CURRENT,
- imgIContainer::FLAG_SYNC_DECODE);
-
- // Ensure that the image's metadata meets our expectations.
- IntSize imageSize(0, 0);
- rv = image->GetWidth(&imageSize.width);
- EXPECT_TRUE(NS_SUCCEEDED(rv));
- rv = image->GetHeight(&imageSize.height);
- EXPECT_TRUE(NS_SUCCEEDED(rv));
-
- EXPECT_EQ(testCase.mSize.width, imageSize.width);
- EXPECT_EQ(testCase.mSize.height, imageSize.height);
-
- Progress imageProgress = tracker->GetProgress();
-
- EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
- EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);
-
- // Ensure that we decoded both frames of the animated version of the image.
- {
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eAnimated));
- ASSERT_EQ(MatchType::EXACT, result.Type());
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
- EXPECT_TRUE(bool(result.Surface()));
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(1)));
- EXPECT_TRUE(bool(result.Surface()));
- }
-
- // Ensure that we didn't decode the static version of the image.
- {
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eStatic));
- ASSERT_EQ(MatchType::NOT_FOUND, result.Type());
- }
-
- // Use GetFrame() to force a sync decode of the image, this time specifying
- // FRAME_FIRST to ensure that we get a single-frame decode.
- RefPtr<SourceSurface> animatedSurface =
- image->GetFrame(imgIContainer::FRAME_FIRST,
- imgIContainer::FLAG_SYNC_DECODE);
-
- // Ensure that we decoded the static version of the image.
- {
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eStatic));
- ASSERT_EQ(MatchType::EXACT, result.Type());
- EXPECT_TRUE(bool(result.Surface()));
- }
-
- // Ensure that both frames of the animated version are still around.
- {
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eAnimated));
- ASSERT_EQ(MatchType::EXACT, result.Type());
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
- EXPECT_TRUE(bool(result.Surface()));
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(1)));
- EXPECT_TRUE(bool(result.Surface()));
- }
-}
-
-TEST_F(ImageDecoders, AnimatedGIFWithExtraImageSubBlocks)
-{
- ImageTestCase testCase = ExtraImageSubBlocksAnimatedGIFTestCase();
-
- // Verify that we can decode this test case and get two frames, even though
- // there are extra image sub blocks between the first and second frame. The
- // extra data shouldn't confuse the decoder or cause the decode to fail.
-
- // Create an image.
- RefPtr<Image> image =
- ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
- ASSERT_TRUE(!image->HasError());
-
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
- ASSERT_TRUE(inputStream);
-
- // Figure out how much data we have.
- uint64_t length;
- nsresult rv = inputStream->Available(&length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Write the data into the image.
- rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
- static_cast<uint32_t>(length));
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Let the image know we've sent all the data.
- rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
- tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
-
- // Use GetFrame() to force a sync decode of the image.
- RefPtr<SourceSurface> surface =
- image->GetFrame(imgIContainer::FRAME_CURRENT,
- imgIContainer::FLAG_SYNC_DECODE);
-
- // Ensure that the image's metadata meets our expectations.
- IntSize imageSize(0, 0);
- rv = image->GetWidth(&imageSize.width);
- EXPECT_TRUE(NS_SUCCEEDED(rv));
- rv = image->GetHeight(&imageSize.height);
- EXPECT_TRUE(NS_SUCCEEDED(rv));
-
- EXPECT_EQ(testCase.mSize.width, imageSize.width);
- EXPECT_EQ(testCase.mSize.height, imageSize.height);
-
- Progress imageProgress = tracker->GetProgress();
-
- EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
- EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);
-
- // Ensure that we decoded both frames of the image.
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eAnimated));
- ASSERT_EQ(MatchType::EXACT, result.Type());
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
- EXPECT_TRUE(bool(result.Surface()));
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(1)));
- EXPECT_TRUE(bool(result.Surface()));
-}
-
-TEST_F(ImageDecoders, TruncatedSmallGIFSingleChunk)
-{
- CheckDecoderSingleChunk(TruncatedSmallGIFTestCase());
-}
diff --git a/image/test/gtest/TestDeinterlacingFilter.cpp b/image/test/gtest/TestDeinterlacingFilter.cpp
deleted file mode 100644
index 82637bbf7..000000000
--- a/image/test/gtest/TestDeinterlacingFilter.cpp
+++ /dev/null
@@ -1,672 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "mozilla/gfx/2D.h"
-#include "Common.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "SourceBuffer.h"
-#include "SurfaceFilters.h"
-#include "SurfacePipe.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-template <typename Func> void
-WithDeinterlacingFilter(const IntSize& aSize,
- bool aProgressiveDisplay,
- Func aFunc)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(bool(decoder));
-
- WithFilterPipeline(decoder, Forward<Func>(aFunc),
- DeinterlacingConfig<uint32_t> { aProgressiveDisplay },
- SurfaceConfig { decoder, aSize,
- SurfaceFormat::B8G8R8A8, false });
-}
-
-template <typename Func> void
-WithPalettedDeinterlacingFilter(const IntSize& aSize,
- Func aFunc)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- WithFilterPipeline(decoder, Forward<Func>(aFunc),
- DeinterlacingConfig<uint8_t> { /* mProgressiveDisplay = */ true },
- PalettedSurfaceConfig { decoder, aSize,
- IntRect(0, 0, 100, 100),
- SurfaceFormat::B8G8R8A8, 8,
- false });
-}
-
-void
-AssertConfiguringDeinterlacingFilterFails(const IntSize& aSize)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- AssertConfiguringPipelineFails(decoder,
- DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true},
- SurfaceConfig { decoder, aSize,
- SurfaceFormat::B8G8R8A8, false });
-}
-
-class ImageDeinterlacingFilter : public ::testing::Test
-{
-protected:
- AutoInitializeImageLib mInit;
-};
-
-TEST_F(ImageDeinterlacingFilter, WritePixels100_100)
-{
- WithDeinterlacingFilter(IntSize(100, 100), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)));
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixels99_99)
-{
- WithDeinterlacingFilter(IntSize(99, 99), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 99, 99)),
- /* aInputRect = */ Some(IntRect(0, 0, 99, 99)));
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixels8_8)
-{
- WithDeinterlacingFilter(IntSize(8, 8), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 8, 8)),
- /* aInputRect = */ Some(IntRect(0, 0, 8, 8)));
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixels7_7)
-{
- WithDeinterlacingFilter(IntSize(7, 7), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 7, 7)),
- /* aInputRect = */ Some(IntRect(0, 0, 7, 7)));
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixels3_3)
-{
- WithDeinterlacingFilter(IntSize(3, 3), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 3, 3)),
- /* aInputRect = */ Some(IntRect(0, 0, 3, 3)));
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixels1_1)
-{
- WithDeinterlacingFilter(IntSize(1, 1), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 1, 1)),
- /* aInputRect = */ Some(IntRect(0, 0, 1, 1)));
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, PalettedWritePixels)
-{
- WithPalettedDeinterlacingFilter(IntSize(100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckPalettedWritePixels(aDecoder, aFilter);
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixelsNonProgressiveOutput51_52)
-{
- WithDeinterlacingFilter(IntSize(51, 52), /* aProgressiveDisplay = */ false,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. The output should be green for even rows and red for odd
- // rows but we need to write the rows in the order that the deinterlacer
- // expects them.
- uint32_t count = 0;
- auto result = aFilter->WritePixels<uint32_t>([&]() {
- uint32_t row = count / 51; // Integer division.
- ++count;
-
- // Note that we use a switch statement here, even though it's quite
- // verbose, because it's useful to have the mappings between input and
- // output rows available when debugging these tests.
-
- switch (row) {
- // First pass. Output rows are positioned at 8n + 0.
- case 0: // Output row 0.
- case 1: // Output row 8.
- case 2: // Output row 16.
- case 3: // Output row 24.
- case 4: // Output row 32.
- case 5: // Output row 40.
- case 6: // Output row 48.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Second pass. Rows are positioned at 8n + 4.
- case 7: // Output row 4.
- case 8: // Output row 12.
- case 9: // Output row 20.
- case 10: // Output row 28.
- case 11: // Output row 36.
- case 12: // Output row 44.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Third pass. Rows are positioned at 4n + 2.
- case 13: // Output row 2.
- case 14: // Output row 6.
- case 15: // Output row 10.
- case 16: // Output row 14.
- case 17: // Output row 18.
- case 18: // Output row 22.
- case 19: // Output row 26.
- case 20: // Output row 30.
- case 21: // Output row 34.
- case 22: // Output row 38.
- case 23: // Output row 42.
- case 24: // Output row 46.
- case 25: // Output row 50.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Fourth pass. Rows are positioned at 2n + 1.
- case 26: // Output row 1.
- case 27: // Output row 3.
- case 28: // Output row 5.
- case 29: // Output row 7.
- case 30: // Output row 9.
- case 31: // Output row 11.
- case 32: // Output row 13.
- case 33: // Output row 15.
- case 34: // Output row 17.
- case 35: // Output row 19.
- case 36: // Output row 21.
- case 37: // Output row 23.
- case 38: // Output row 25.
- case 39: // Output row 27.
- case 40: // Output row 29.
- case 41: // Output row 31.
- case 42: // Output row 33.
- case 43: // Output row 35.
- case 44: // Output row 37.
- case 45: // Output row 39.
- case 46: // Output row 41.
- case 47: // Output row 43.
- case 48: // Output row 45.
- case 49: // Output row 47.
- case 50: // Output row 49.
- case 51: // Output row 51.
- return AsVariant(BGRAColor::Red().AsPixel());
-
- default:
- MOZ_ASSERT_UNREACHABLE("Unexpected row");
- return AsVariant(BGRAColor::Transparent().AsPixel());
- }
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(51u * 52u, count);
-
- AssertCorrectPipelineFinalState(aFilter,
- IntRect(0, 0, 51, 52),
- IntRect(0, 0, 51, 52));
-
- // Check that the generated image is correct. As mentioned above, we expect
- // even rows to be green and odd rows to be red.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- for (uint32_t row = 0; row < 52; ++row) {
- EXPECT_TRUE(RowsAreSolidColor(surface, row, 1,
- row % 2 == 0 ? BGRAColor::Green()
- : BGRAColor::Red()));
- }
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixelsOutput20_20)
-{
- WithDeinterlacingFilter(IntSize(20, 20), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. The output should be green for even rows and red for odd
- // rows but we need to write the rows in the order that the deinterlacer
- // expects them.
- uint32_t count = 0;
- auto result = aFilter->WritePixels<uint32_t>([&]() {
- uint32_t row = count / 20; // Integer division.
- ++count;
-
- // Note that we use a switch statement here, even though it's quite
- // verbose, because it's useful to have the mappings between input and
- // output rows available when debugging these tests.
-
- switch (row) {
- // First pass. Output rows are positioned at 8n + 0.
- case 0: // Output row 0.
- case 1: // Output row 8.
- case 2: // Output row 16.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Second pass. Rows are positioned at 8n + 4.
- case 3: // Output row 4.
- case 4: // Output row 12.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Third pass. Rows are positioned at 4n + 2.
- case 5: // Output row 2.
- case 6: // Output row 6.
- case 7: // Output row 10.
- case 8: // Output row 14.
- case 9: // Output row 18.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Fourth pass. Rows are positioned at 2n + 1.
- case 10: // Output row 1.
- case 11: // Output row 3.
- case 12: // Output row 5.
- case 13: // Output row 7.
- case 14: // Output row 9.
- case 15: // Output row 11.
- case 16: // Output row 13.
- case 17: // Output row 15.
- case 18: // Output row 17.
- case 19: // Output row 19.
- return AsVariant(BGRAColor::Red().AsPixel());
-
- default:
- MOZ_ASSERT_UNREACHABLE("Unexpected row");
- return AsVariant(BGRAColor::Transparent().AsPixel());
- }
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(20u * 20u, count);
-
- AssertCorrectPipelineFinalState(aFilter,
- IntRect(0, 0, 20, 20),
- IntRect(0, 0, 20, 20));
-
- // Check that the generated image is correct. As mentioned above, we expect
- // even rows to be green and odd rows to be red.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- for (uint32_t row = 0; row < 20; ++row) {
- EXPECT_TRUE(RowsAreSolidColor(surface, row, 1,
- row % 2 == 0 ? BGRAColor::Green()
- : BGRAColor::Red()));
- }
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixelsOutput7_7)
-{
- WithDeinterlacingFilter(IntSize(7, 7), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. The output should be a repeating pattern of two green
- // rows followed by two red rows but we need to write the rows in the order
- // that the deinterlacer expects them.
- uint32_t count = 0;
- auto result = aFilter->WritePixels<uint32_t>([&]() {
- uint32_t row = count / 7; // Integer division.
- ++count;
-
- switch (row) {
- // First pass. Output rows are positioned at 8n + 0.
- case 0: // Output row 0.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Second pass. Rows are positioned at 8n + 4.
- case 1: // Output row 4.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Third pass. Rows are positioned at 4n + 2.
- case 2: // Output row 2.
- case 3: // Output row 6.
- return AsVariant(BGRAColor::Red().AsPixel());
-
- // Fourth pass. Rows are positioned at 2n + 1.
- case 4: // Output row 1.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- case 5: // Output row 3.
- return AsVariant(BGRAColor::Red().AsPixel());
-
- case 6: // Output row 5.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- default:
- MOZ_ASSERT_UNREACHABLE("Unexpected row");
- return AsVariant(BGRAColor::Transparent().AsPixel());
- }
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(7u * 7u, count);
-
- AssertCorrectPipelineFinalState(aFilter,
- IntRect(0, 0, 7, 7),
- IntRect(0, 0, 7, 7));
-
- // Check that the generated image is correct. As mentioned above, we expect
- // two green rows, followed by two red rows, then two green rows, etc.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- for (uint32_t row = 0; row < 7; ++row) {
- BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
- ? BGRAColor::Green()
- : BGRAColor::Red();
- EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
- }
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixelsOutput3_3)
-{
- WithDeinterlacingFilter(IntSize(3, 3), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. The output should be green, red, green in that order, but
- // we need to write the rows in the order that the deinterlacer expects
- // them.
- uint32_t count = 0;
- auto result = aFilter->WritePixels<uint32_t>([&]() {
- uint32_t row = count / 3; // Integer division.
- ++count;
-
- switch (row) {
- // First pass. Output rows are positioned at 8n + 0.
- case 0: // Output row 0.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Second pass. Rows are positioned at 8n + 4.
- // No rows for this pass.
-
- // Third pass. Rows are positioned at 4n + 2.
- case 1: // Output row 2.
- return AsVariant(BGRAColor::Green().AsPixel());
-
- // Fourth pass. Rows are positioned at 2n + 1.
- case 2: // Output row 1.
- return AsVariant(BGRAColor::Red().AsPixel());
-
- default:
- MOZ_ASSERT_UNREACHABLE("Unexpected row");
- return AsVariant(BGRAColor::Transparent().AsPixel());
- }
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(3u * 3u, count);
-
- AssertCorrectPipelineFinalState(aFilter,
- IntRect(0, 0, 3, 3),
- IntRect(0, 0, 3, 3));
-
- // Check that the generated image is correct. As mentioned above, we expect
- // green, red, green in that order.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- for (uint32_t row = 0; row < 3; ++row) {
- EXPECT_TRUE(RowsAreSolidColor(surface, row, 1,
- row == 0 || row == 2 ? BGRAColor::Green()
- : BGRAColor::Red()));
- }
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixelsOutput1_1)
-{
- WithDeinterlacingFilter(IntSize(1, 1), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. The output should be a single red row.
- uint32_t count = 0;
- auto result = aFilter->WritePixels<uint32_t>([&]() {
- ++count;
- return AsVariant(BGRAColor::Red().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(1u, count);
-
- AssertCorrectPipelineFinalState(aFilter,
- IntRect(0, 0, 1, 1),
- IntRect(0, 0, 1, 1));
-
- // Check that the generated image is correct. As mentioned above, we expect
- // a single red row.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- EXPECT_TRUE(RowsAreSolidColor(surface, 0, 1, BGRAColor::Red()));
- });
-}
-
-void
-WriteRowAndCheckInterlacerOutput(Decoder* aDecoder,
- SurfaceFilter* aFilter,
- BGRAColor aColor,
- WriteState aNextState,
- IntRect aInvalidRect,
- uint32_t aFirstHaeberliRow,
- uint32_t aLastHaeberliRow)
-{
- uint32_t count = 0;
-
- auto result = aFilter->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count < 7) {
- ++count;
- return AsVariant(aColor.AsPixel());
- }
- return AsVariant(WriteState::NEED_MORE_DATA);
- });
-
- EXPECT_EQ(aNextState, result);
- EXPECT_EQ(7u, count);
-
- // Assert that we got the expected invalidation region.
- Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(aInvalidRect, invalidRect->mInputSpaceRect);
- EXPECT_EQ(aInvalidRect, invalidRect->mOutputSpaceRect);
-
- // Check that the portion of the image generated so far is correct. The rows
- // from aFirstHaeberliRow to aLastHaeberliRow should be filled with aColor.
- // Note that this is not the same as the set of rows in aInvalidRect, because
- // after writing a row the deinterlacer seeks to the next row to write, which
- // may involve copying previously-written rows in the buffer to the output
- // even though they don't change in this pass.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- for (uint32_t row = aFirstHaeberliRow; row <= aLastHaeberliRow; ++row) {
- EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, aColor));
- }
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixelsIntermediateOutput7_7)
-{
- WithDeinterlacingFilter(IntSize(7, 7), /* aProgressiveDisplay = */ true,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. The output should be a repeating pattern of two green
- // rows followed by two red rows but we need to write the rows in the order
- // that the deinterlacer expects them.
-
- // First pass. Output rows are positioned at 8n + 0.
-
- // Output row 0. The invalid rect is the entire image because this is the
- // end of the first pass.
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 0, 7, 7), 0, 4);
-
- // Second pass. Rows are positioned at 8n + 4.
-
- // Output row 4. The invalid rect is the entire image because this is the
- // end of the second pass.
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 0, 7, 7), 1, 4);
-
- // Third pass. Rows are positioned at 4n + 2.
-
- // Output row 2. The invalid rect contains the Haeberli rows for this output
- // row (rows 2 and 3) as well as the rows that we copy from previous passes
- // when seeking to the next output row (rows 4 and 5).
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 2, 7, 4), 2, 3);
-
- // Output row 6. The invalid rect is the entire image because this is the
- // end of the third pass.
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 0, 7, 7), 6, 6);
-
- // Fourth pass. Rows are positioned at 2n + 1.
-
- // Output row 1. The invalid rect contains the Haeberli rows for this output
- // row (just row 1) as well as the rows that we copy from previous passes
- // when seeking to the next output row (row 2).
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 1, 7, 2), 1, 1);
-
- // Output row 3. The invalid rect contains the Haeberli rows for this output
- // row (just row 3) as well as the rows that we copy from previous passes
- // when seeking to the next output row (row 4).
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 3, 7, 2), 3, 3);
-
- // Output row 5. The invalid rect contains the Haeberli rows for this output
- // row (just row 5) as well as the rows that we copy from previous passes
- // when seeking to the next output row (row 6).
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
- WriteState::FINISHED,
- IntRect(0, 5, 7, 2), 5, 5);
-
- // Assert that we're in the expected final state.
- EXPECT_TRUE(aFilter->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Check that the generated image is correct. As mentioned above, we expect
- // two green rows, followed by two red rows, then two green rows, etc.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- for (uint32_t row = 0; row < 7; ++row) {
- BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
- ? BGRAColor::Green()
- : BGRAColor::Red();
- EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
- }
- });
-}
-
-TEST_F(ImageDeinterlacingFilter, WritePixelsNonProgressiveIntermediateOutput7_7)
-{
- WithDeinterlacingFilter(IntSize(7, 7), /* aProgressiveDisplay = */ false,
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. The output should be a repeating pattern of two green
- // rows followed by two red rows but we need to write the rows in the order
- // that the deinterlacer expects them.
-
- // First pass. Output rows are positioned at 8n + 0.
-
- // Output row 0. The invalid rect is the entire image because this is the
- // end of the first pass.
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 0, 7, 7), 0, 0);
-
- // Second pass. Rows are positioned at 8n + 4.
-
- // Output row 4. The invalid rect is the entire image because this is the
- // end of the second pass.
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 0, 7, 7), 4, 4);
-
- // Third pass. Rows are positioned at 4n + 2.
-
- // Output row 2. The invalid rect contains the Haeberli rows for this output
- // row (rows 2 and 3) as well as the rows that we copy from previous passes
- // when seeking to the next output row (rows 4 and 5).
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 2, 7, 4), 2, 2);
-
- // Output row 6. The invalid rect is the entire image because this is the
- // end of the third pass.
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 0, 7, 7), 6, 6);
-
- // Fourth pass. Rows are positioned at 2n + 1.
-
- // Output row 1. The invalid rect contains the Haeberli rows for this output
- // row (just row 1) as well as the rows that we copy from previous passes
- // when seeking to the next output row (row 2).
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 1, 7, 2), 1, 1);
-
- // Output row 3. The invalid rect contains the Haeberli rows for this output
- // row (just row 3) as well as the rows that we copy from previous passes
- // when seeking to the next output row (row 4).
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Red(),
- WriteState::NEED_MORE_DATA,
- IntRect(0, 3, 7, 2), 3, 3);
-
- // Output row 5. The invalid rect contains the Haeberli rows for this output
- // row (just row 5) as well as the rows that we copy from previous passes
- // when seeking to the next output row (row 6).
- WriteRowAndCheckInterlacerOutput(aDecoder, aFilter, BGRAColor::Green(),
- WriteState::FINISHED,
- IntRect(0, 5, 7, 2), 5, 5);
-
- // Assert that we're in the expected final state.
- EXPECT_TRUE(aFilter->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aFilter->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Check that the generated image is correct. As mentioned above, we expect
- // two green rows, followed by two red rows, then two green rows, etc.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- for (uint32_t row = 0; row < 7; ++row) {
- BGRAColor color = row == 0 || row == 1 || row == 4 || row == 5
- ? BGRAColor::Green()
- : BGRAColor::Red();
- EXPECT_TRUE(RowsAreSolidColor(surface, row, 1, color));
- }
- });
-}
-
-
-TEST_F(ImageDeinterlacingFilter, DeinterlacingFailsFor0_0)
-{
- // A 0x0 input size is invalid, so configuration should fail.
- AssertConfiguringDeinterlacingFilterFails(IntSize(0, 0));
-}
-
-TEST_F(ImageDeinterlacingFilter, DeinterlacingFailsForMinus1_Minus1)
-{
- // A negative input size is invalid, so configuration should fail.
- AssertConfiguringDeinterlacingFilterFails(IntSize(-1, -1));
-}
diff --git a/image/test/gtest/TestDownscalingFilter.cpp b/image/test/gtest/TestDownscalingFilter.cpp
deleted file mode 100644
index d7aa0ead2..000000000
--- a/image/test/gtest/TestDownscalingFilter.cpp
+++ /dev/null
@@ -1,231 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "mozilla/gfx/2D.h"
-#include "Common.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "SourceBuffer.h"
-#include "SurfaceFilters.h"
-#include "SurfacePipe.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-template <typename Func> void
-WithDownscalingFilter(const IntSize& aInputSize,
- const IntSize& aOutputSize,
- Func aFunc)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- WithFilterPipeline(decoder, Forward<Func>(aFunc),
- DownscalingConfig { aInputSize,
- SurfaceFormat::B8G8R8A8 },
- SurfaceConfig { decoder, aOutputSize,
- SurfaceFormat::B8G8R8A8, false });
-}
-
-void
-AssertConfiguringDownscalingFilterFails(const IntSize& aInputSize,
- const IntSize& aOutputSize)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- AssertConfiguringPipelineFails(decoder,
- DownscalingConfig { aInputSize,
- SurfaceFormat::B8G8R8A8 },
- SurfaceConfig { decoder, aOutputSize,
- SurfaceFormat::B8G8R8A8, false });
-}
-
-TEST(ImageDownscalingFilter, WritePixels100_100to99_99)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(99, 99),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 99, 99)));
- });
-}
-
-TEST(ImageDownscalingFilter, WritePixels100_100to33_33)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(33, 33),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 33, 33)));
- });
-}
-
-TEST(ImageDownscalingFilter, WritePixels100_100to1_1)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(1, 1),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 1, 1)));
- });
-}
-
-TEST(ImageDownscalingFilter, WritePixels100_100to33_99)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(33, 99),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 33, 99)));
- });
-}
-
-TEST(ImageDownscalingFilter, WritePixels100_100to99_33)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(99, 33),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 99, 33)));
- });
-}
-
-TEST(ImageDownscalingFilter, WritePixels100_100to99_1)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(99, 1),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 99, 1)));
- });
-}
-
-TEST(ImageDownscalingFilter, WritePixels100_100to1_99)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(1, 99),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 1, 99)));
- });
-}
-
-TEST(ImageDownscalingFilter, DownscalingFailsFor100_100to101_101)
-{
- // Upscaling is disallowed.
- AssertConfiguringDownscalingFilterFails(IntSize(100, 100), IntSize(101, 101));
-}
-
-TEST(ImageDownscalingFilter, DownscalingFailsFor100_100to100_100)
-{
- // "Scaling" to the same size is disallowed.
- AssertConfiguringDownscalingFilterFails(IntSize(100, 100), IntSize(100, 100));
-}
-
-TEST(ImageDownscalingFilter, DownscalingFailsFor0_0toMinus1_Minus1)
-{
- // A 0x0 input size is disallowed.
- AssertConfiguringDownscalingFilterFails(IntSize(0, 0), IntSize(-1, -1));
-}
-
-TEST(ImageDownscalingFilter, DownscalingFailsForMinus1_Minus1toMinus2_Minus2)
-{
- // A negative input size is disallowed.
- AssertConfiguringDownscalingFilterFails(IntSize(-1, -1), IntSize(-2, -2));
-}
-
-TEST(ImageDownscalingFilter, DownscalingFailsFor100_100to0_0)
-{
- // A 0x0 output size is disallowed.
- AssertConfiguringDownscalingFilterFails(IntSize(100, 100), IntSize(0, 0));
-}
-
-TEST(ImageDownscalingFilter, DownscalingFailsFor100_100toMinus1_Minus1)
-{
- // A negative output size is disallowed.
- AssertConfiguringDownscalingFilterFails(IntSize(100, 100), IntSize(-1, -1));
-}
-
-TEST(ImageDownscalingFilter, WritePixelsOutput100_100to20_20)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(20, 20),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. It consists of 25 lines of green, followed by 25 lines of
- // red, followed by 25 lines of green, followed by 25 more lines of red.
- uint32_t count = 0;
- auto result = aFilter->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- uint32_t color = (count <= 25 * 100) || (count > 50 * 100 && count <= 75 * 100)
- ? BGRAColor::Green().AsPixel()
- : BGRAColor::Red().AsPixel();
- ++count;
- return AsVariant(color);
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
-
- AssertCorrectPipelineFinalState(aFilter,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 20, 20));
-
- // Check that the generated image is correct. Note that we skip rows near
- // the transitions between colors, since the downscaler does not produce a
- // sharp boundary at these points. Even some of the rows we test need a
- // small amount of fuzz; this is just the nature of Lanczos downscaling.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(RowsAreSolidColor(surface, 0, 4, BGRAColor::Green(), /* aFuzz = */ 2));
- EXPECT_TRUE(RowsAreSolidColor(surface, 6, 3, BGRAColor::Red(), /* aFuzz = */ 3));
- EXPECT_TRUE(RowsAreSolidColor(surface, 11, 3, BGRAColor::Green(), /* aFuzz = */ 3));
- EXPECT_TRUE(RowsAreSolidColor(surface, 16, 4, BGRAColor::Red(), /* aFuzz = */ 3));
- });
-}
-
-TEST(ImageDownscalingFilter, WritePixelsOutput100_100to10_20)
-{
- WithDownscalingFilter(IntSize(100, 100), IntSize(10, 20),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Fill the image. It consists of 25 lines of green, followed by 25 lines of
- // red, followed by 25 lines of green, followed by 25 more lines of red.
- uint32_t count = 0;
- auto result = aFilter->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- uint32_t color = (count <= 25 * 100) || (count > 50 * 100 && count <= 75 * 100)
- ? BGRAColor::Green().AsPixel()
- : BGRAColor::Red().AsPixel();
- ++count;
- return AsVariant(color);
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
-
- AssertCorrectPipelineFinalState(aFilter,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 10, 20));
-
- // Check that the generated image is correct. Note that we skip rows near
- // the transitions between colors, since the downscaler does not produce a
- // sharp boundary at these points. Even some of the rows we test need a
- // small amount of fuzz; this is just the nature of Lanczos downscaling.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(RowsAreSolidColor(surface, 0, 4, BGRAColor::Green(), /* aFuzz = */ 2));
- EXPECT_TRUE(RowsAreSolidColor(surface, 6, 3, BGRAColor::Red(), /* aFuzz = */ 3));
- EXPECT_TRUE(RowsAreSolidColor(surface, 11, 3, BGRAColor::Green(), /* aFuzz = */ 3));
- EXPECT_TRUE(RowsAreSolidColor(surface, 16, 4, BGRAColor::Red(), /* aFuzz = */ 3));
- });
-}
-
-TEST(ImageDownscalingFilter, ConfiguringPalettedDownscaleFails)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- // DownscalingFilter does not support paletted images, so configuration should
- // fail.
- AssertConfiguringPipelineFails(decoder,
- DownscalingConfig { IntSize(100, 100),
- SurfaceFormat::B8G8R8A8 },
- PalettedSurfaceConfig { decoder, IntSize(20, 20),
- IntRect(0, 0, 20, 20),
- SurfaceFormat::B8G8R8A8, 8,
- false });
-}
diff --git a/image/test/gtest/TestDownscalingFilterNoSkia.cpp b/image/test/gtest/TestDownscalingFilterNoSkia.cpp
deleted file mode 100644
index 80928a880..000000000
--- a/image/test/gtest/TestDownscalingFilterNoSkia.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "mozilla/gfx/2D.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "SourceBuffer.h"
-#include "SurfacePipe.h"
-
-// We want to ensure that we're testing the non-Skia fallback version of
-// DownscalingFilter, but there are two issues:
-// (1) We don't know whether Skia is currently enabled.
-// (2) If we force disable it, the disabled version will get linked into the
-// binary and will cause the tests in TestDownscalingFilter to fail.
-// To avoid these problems, we ensure that MOZ_ENABLE_SKIA is defined when
-// including DownscalingFilter.h, and we use the preprocessor to redefine the
-// DownscalingFilter class to DownscalingFilterNoSkia.
-
-#define DownscalingFilter DownscalingFilterNoSkia
-
-#ifdef MOZ_ENABLE_SKIA
-
-#undef MOZ_ENABLE_SKIA
-#include "Common.h"
-#include "DownscalingFilter.h"
-#define MOZ_ENABLE_SKIA
-
-#else
-
-#include "Common.h"
-#include "DownscalingFilter.h"
-
-#endif
-
-#undef DownscalingFilter
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-TEST(ImageDownscalingFilter, NoSkia)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(bool(decoder));
-
- // Configuring a DownscalingFilter should fail without Skia.
- AssertConfiguringPipelineFails(decoder,
- DownscalingConfig { IntSize(100, 100),
- SurfaceFormat::B8G8R8A8 },
- SurfaceConfig { decoder, IntSize(50, 50),
- SurfaceFormat::B8G8R8A8, false });
-}
diff --git a/image/test/gtest/TestLoader.cpp b/image/test/gtest/TestLoader.cpp
deleted file mode 100644
index 5551f3f05..000000000
--- a/image/test/gtest/TestLoader.cpp
+++ /dev/null
@@ -1,84 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "Common.h"
-#include "imgLoader.h"
-#include "nsMimeTypes.h"
-#include "nsString.h"
-
-using namespace mozilla;
-using namespace mozilla::image;
-
-static void
-CheckMimeType(const char* aContents, size_t aLength, const char* aExpected)
-{
- nsAutoCString detected;
- nsresult rv = imgLoader::GetMimeTypeFromContent(aContents, aLength, detected);
- if (aExpected) {
- ASSERT_TRUE(NS_SUCCEEDED(rv));
- EXPECT_TRUE(detected.EqualsASCII(aExpected));
- } else {
- ASSERT_TRUE(NS_FAILED(rv));
- EXPECT_TRUE(detected.IsEmpty());
- }
-}
-
-class ImageLoader : public ::testing::Test
-{
-protected:
- AutoInitializeImageLib mInit;
-};
-
-TEST_F(ImageLoader, DetectGIF)
-{
- const char buffer[] = "GIF87a";
- CheckMimeType(buffer, sizeof(buffer), IMAGE_GIF);
-}
-
-TEST_F(ImageLoader, DetectPNG)
-{
- const char buffer[] = "\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
- CheckMimeType(buffer, sizeof(buffer), IMAGE_PNG);
-}
-
-TEST_F(ImageLoader, DetectJPEG)
-{
- const char buffer[] = "\xFF\xD8\xFF";
- CheckMimeType(buffer, sizeof(buffer), IMAGE_JPEG);
-}
-
-TEST_F(ImageLoader, DetectART)
-{
- const char buffer[] = "\x4A\x47\xFF\xFF\x00";
- CheckMimeType(buffer, sizeof(buffer), IMAGE_ART);
-}
-
-TEST_F(ImageLoader, DetectBMP)
-{
- const char buffer[] = "BM";
- CheckMimeType(buffer, sizeof(buffer), IMAGE_BMP);
-}
-
-TEST_F(ImageLoader, DetectICO)
-{
- const char buffer[] = "\x00\x00\x01\x00";
- CheckMimeType(buffer, sizeof(buffer), IMAGE_ICO);
-}
-
-TEST_F(ImageLoader, DetectWebP)
-{
- const char buffer[] = "RIFF\xFF\xFF\xFF\xFFWEBPVP8L";
- CheckMimeType(buffer, sizeof(buffer), IMAGE_WEBP);
-}
-
-TEST_F(ImageLoader, DetectNone)
-{
- const char buffer[] = "abcdefghijklmnop";
- CheckMimeType(buffer, sizeof(buffer), nullptr);
-}
-
diff --git a/image/test/gtest/TestMetadata.cpp b/image/test/gtest/TestMetadata.cpp
deleted file mode 100644
index 9f3a64898..000000000
--- a/image/test/gtest/TestMetadata.cpp
+++ /dev/null
@@ -1,255 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "Common.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "decoders/nsBMPDecoder.h"
-#include "IDecodingTask.h"
-#include "imgIContainer.h"
-#include "imgITools.h"
-#include "ImageFactory.h"
-#include "mozilla/gfx/2D.h"
-#include "nsComponentManagerUtils.h"
-#include "nsCOMPtr.h"
-#include "nsIInputStream.h"
-#include "nsIRunnable.h"
-#include "nsIThread.h"
-#include "mozilla/RefPtr.h"
-#include "nsStreamUtils.h"
-#include "nsString.h"
-#include "nsThreadUtils.h"
-#include "ProgressTracker.h"
-#include "SourceBuffer.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-enum class BMPWithinICO
-{
- NO,
- YES
-};
-
-static void
-CheckMetadata(const ImageTestCase& aTestCase,
- BMPWithinICO aBMPWithinICO = BMPWithinICO::NO)
-{
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
- ASSERT_TRUE(inputStream != nullptr);
-
- // Figure out how much data we have.
- uint64_t length;
- nsresult rv = inputStream->Available(&length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Write the data into a SourceBuffer.
- NotNull<RefPtr<SourceBuffer>> sourceBuffer = WrapNotNull(new SourceBuffer());
- sourceBuffer->ExpectLength(length);
- rv = sourceBuffer->AppendFromInputStream(inputStream, length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
- sourceBuffer->Complete(NS_OK);
-
- // Create a metadata decoder.
- DecoderType decoderType =
- DecoderFactory::GetDecoderType(aTestCase.mMimeType);
- RefPtr<Decoder> decoder =
- DecoderFactory::CreateAnonymousMetadataDecoder(decoderType, sourceBuffer);
- ASSERT_TRUE(decoder != nullptr);
- RefPtr<IDecodingTask> task = new AnonymousDecodingTask(WrapNotNull(decoder));
-
- if (aBMPWithinICO == BMPWithinICO::YES) {
- static_cast<nsBMPDecoder*>(decoder.get())->SetIsWithinICO();
- }
-
- // Run the metadata decoder synchronously.
- task->Run();
-
- // Ensure that the metadata decoder didn't make progress it shouldn't have
- // (which would indicate that it decoded past the header of the image).
- Progress metadataProgress = decoder->TakeProgress();
- EXPECT_TRUE(0 == (metadataProgress & ~(FLAG_SIZE_AVAILABLE |
- FLAG_HAS_TRANSPARENCY |
- FLAG_IS_ANIMATED)));
-
- // If the test case is corrupt, assert what we can and return early.
- if (aTestCase.mFlags & TEST_CASE_HAS_ERROR) {
- EXPECT_TRUE(decoder->GetDecodeDone());
- EXPECT_TRUE(decoder->HasError());
- return;
- }
-
- EXPECT_TRUE(decoder->GetDecodeDone() && !decoder->HasError());
-
- // Check that we got the expected metadata.
- EXPECT_TRUE(metadataProgress & FLAG_SIZE_AVAILABLE);
-
- IntSize metadataSize = decoder->Size();
- EXPECT_EQ(aTestCase.mSize.width, metadataSize.width);
- EXPECT_EQ(aTestCase.mSize.height, metadataSize.height);
-
- bool expectTransparency = aBMPWithinICO == BMPWithinICO::YES
- ? true
- : bool(aTestCase.mFlags & TEST_CASE_IS_TRANSPARENT);
- EXPECT_EQ(expectTransparency, bool(metadataProgress & FLAG_HAS_TRANSPARENCY));
-
- EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_ANIMATED),
- bool(metadataProgress & FLAG_IS_ANIMATED));
-
- // Create a full decoder, so we can compare the result.
- decoder =
- DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(),
- DefaultSurfaceFlags());
- ASSERT_TRUE(decoder != nullptr);
- task = new AnonymousDecodingTask(WrapNotNull(decoder));
-
- if (aBMPWithinICO == BMPWithinICO::YES) {
- static_cast<nsBMPDecoder*>(decoder.get())->SetIsWithinICO();
- }
-
- // Run the full decoder synchronously.
- task->Run();
-
- EXPECT_TRUE(decoder->GetDecodeDone() && !decoder->HasError());
- Progress fullProgress = decoder->TakeProgress();
-
- // If the metadata decoder set a progress bit, the full decoder should also
- // have set the same bit.
- EXPECT_EQ(fullProgress, metadataProgress | fullProgress);
-
- // The full decoder and the metadata decoder should agree on the image's size.
- IntSize fullSize = decoder->Size();
- EXPECT_EQ(metadataSize.width, fullSize.width);
- EXPECT_EQ(metadataSize.height, fullSize.height);
-
- // We should not discover transparency during the full decode that we didn't
- // discover during the metadata decode, unless the image is animated.
- EXPECT_TRUE(!(fullProgress & FLAG_HAS_TRANSPARENCY) ||
- (metadataProgress & FLAG_HAS_TRANSPARENCY) ||
- (fullProgress & FLAG_IS_ANIMATED));
-}
-
-class ImageDecoderMetadata : public ::testing::Test
-{
-protected:
- AutoInitializeImageLib mInit;
-};
-
-TEST_F(ImageDecoderMetadata, PNG) { CheckMetadata(GreenPNGTestCase()); }
-TEST_F(ImageDecoderMetadata, TransparentPNG) { CheckMetadata(TransparentPNGTestCase()); }
-TEST_F(ImageDecoderMetadata, GIF) { CheckMetadata(GreenGIFTestCase()); }
-TEST_F(ImageDecoderMetadata, TransparentGIF) { CheckMetadata(TransparentGIFTestCase()); }
-TEST_F(ImageDecoderMetadata, JPG) { CheckMetadata(GreenJPGTestCase()); }
-TEST_F(ImageDecoderMetadata, BMP) { CheckMetadata(GreenBMPTestCase()); }
-TEST_F(ImageDecoderMetadata, ICO) { CheckMetadata(GreenICOTestCase()); }
-TEST_F(ImageDecoderMetadata, Icon) { CheckMetadata(GreenIconTestCase()); }
-
-TEST_F(ImageDecoderMetadata, AnimatedGIF)
-{
- CheckMetadata(GreenFirstFrameAnimatedGIFTestCase());
-}
-
-TEST_F(ImageDecoderMetadata, AnimatedPNG)
-{
- CheckMetadata(GreenFirstFrameAnimatedPNGTestCase());
-}
-
-TEST_F(ImageDecoderMetadata, FirstFramePaddingGIF)
-{
- CheckMetadata(FirstFramePaddingGIFTestCase());
-}
-
-TEST_F(ImageDecoderMetadata, TransparentIfWithinICOBMPNotWithinICO)
-{
- CheckMetadata(TransparentIfWithinICOBMPTestCase(TEST_CASE_DEFAULT_FLAGS),
- BMPWithinICO::NO);
-}
-
-TEST_F(ImageDecoderMetadata, TransparentIfWithinICOBMPWithinICO)
-{
- CheckMetadata(TransparentIfWithinICOBMPTestCase(TEST_CASE_IS_TRANSPARENT),
- BMPWithinICO::YES);
-}
-
-TEST_F(ImageDecoderMetadata, RLE4BMP) { CheckMetadata(RLE4BMPTestCase()); }
-TEST_F(ImageDecoderMetadata, RLE8BMP) { CheckMetadata(RLE8BMPTestCase()); }
-
-TEST_F(ImageDecoderMetadata, Corrupt) { CheckMetadata(CorruptTestCase()); }
-
-TEST_F(ImageDecoderMetadata, NoFrameDelayGIF)
-{
- CheckMetadata(NoFrameDelayGIFTestCase());
-}
-
-TEST_F(ImageDecoderMetadata, NoFrameDelayGIFFullDecode)
-{
- ImageTestCase testCase = NoFrameDelayGIFTestCase();
-
- // The previous test (NoFrameDelayGIF) verifies that we *don't* detect that
- // this test case is animated, because it has a zero frame delay for the first
- // frame. This test verifies that when we do a full decode, we detect the
- // animation at that point and successfully decode all the frames.
-
- // Create an image.
- RefPtr<Image> image =
- ImageFactory::CreateAnonymousImage(nsDependentCString(testCase.mMimeType));
- ASSERT_TRUE(!image->HasError());
-
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath);
- ASSERT_TRUE(inputStream != nullptr);
-
- // Figure out how much data we have.
- uint64_t length;
- nsresult rv = inputStream->Available(&length);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Write the data into the image.
- rv = image->OnImageDataAvailable(nullptr, nullptr, inputStream, 0,
- static_cast<uint32_t>(length));
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- // Let the image know we've sent all the data.
- rv = image->OnImageDataComplete(nullptr, nullptr, NS_OK, true);
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- RefPtr<ProgressTracker> tracker = image->GetProgressTracker();
- tracker->SyncNotifyProgress(FLAG_LOAD_COMPLETE);
-
- // Use GetFrame() to force a sync decode of the image.
- RefPtr<SourceSurface> surface =
- image->GetFrame(imgIContainer::FRAME_CURRENT,
- imgIContainer::FLAG_SYNC_DECODE);
-
- // Ensure that the image's metadata meets our expectations.
- IntSize imageSize(0, 0);
- rv = image->GetWidth(&imageSize.width);
- EXPECT_TRUE(NS_SUCCEEDED(rv));
- rv = image->GetHeight(&imageSize.height);
- EXPECT_TRUE(NS_SUCCEEDED(rv));
-
- EXPECT_EQ(testCase.mSize.width, imageSize.width);
- EXPECT_EQ(testCase.mSize.height, imageSize.height);
-
- Progress imageProgress = tracker->GetProgress();
-
- EXPECT_TRUE(bool(imageProgress & FLAG_HAS_TRANSPARENCY) == false);
- EXPECT_TRUE(bool(imageProgress & FLAG_IS_ANIMATED) == true);
-
- // Ensure that we decoded both frames of the image.
- LookupResult result =
- SurfaceCache::Lookup(ImageKey(image.get()),
- RasterSurfaceKey(imageSize,
- DefaultSurfaceFlags(),
- PlaybackType::eAnimated));
- ASSERT_EQ(MatchType::EXACT, result.Type());
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(0)));
- EXPECT_TRUE(bool(result.Surface()));
-
- EXPECT_TRUE(NS_SUCCEEDED(result.Surface().Seek(1)));
- EXPECT_TRUE(bool(result.Surface()));
-}
diff --git a/image/test/gtest/TestRemoveFrameRectFilter.cpp b/image/test/gtest/TestRemoveFrameRectFilter.cpp
deleted file mode 100644
index ad1f944fc..000000000
--- a/image/test/gtest/TestRemoveFrameRectFilter.cpp
+++ /dev/null
@@ -1,327 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "mozilla/gfx/2D.h"
-#include "Common.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "SourceBuffer.h"
-#include "SurfaceFilters.h"
-#include "SurfacePipe.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-template <typename Func> void
-WithRemoveFrameRectFilter(const IntSize& aSize,
- const IntRect& aFrameRect,
- Func aFunc)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- WithFilterPipeline(decoder, Forward<Func>(aFunc),
- RemoveFrameRectConfig { aFrameRect },
- SurfaceConfig { decoder, aSize,
- SurfaceFormat::B8G8R8A8, false });
-}
-
-void
-AssertConfiguringRemoveFrameRectFilterFails(const IntSize& aSize,
- const IntRect& aFrameRect)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- AssertConfiguringPipelineFails(decoder,
- RemoveFrameRectConfig { aFrameRect },
- SurfaceConfig { decoder, aSize,
- SurfaceFormat::B8G8R8A8, false });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_0_0_100_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 100, 100)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_0_0_0_0)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(0, 0, 0, 0),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_Minus50_50_0_0)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(-50, 50, 0, 0),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_50_Minus50_0_0)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(50, -50, 0, 0),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_150_50_0_0)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(150, 50, 0, 0),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_50_150_0_0)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(50, 150, 0, 0),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_200_200_100_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(200, 200, 100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Note that aInputRect is zero-size because RemoveFrameRectFilter ignores
- // trailing rows that don't show up in the output. (Leading rows
- // unfortunately can't be ignored.)
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_Minus200_25_100_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(-200, 25, 100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Note that aInputRect is zero-size because RemoveFrameRectFilter ignores
- // trailing rows that don't show up in the output. (Leading rows
- // unfortunately can't be ignored.)
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_25_Minus200_100_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(25, -200, 100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Note that aInputRect is zero-size because RemoveFrameRectFilter ignores
- // trailing rows that don't show up in the output. (Leading rows
- // unfortunately can't be ignored.)
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_200_25_100_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(200, 25, 100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Note that aInputRect is zero-size because RemoveFrameRectFilter ignores
- // trailing rows that don't show up in the output. (Leading rows
- // unfortunately can't be ignored.)
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_25_200_100_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(25, 200, 100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Note that aInputRect is zero-size because RemoveFrameRectFilter ignores
- // trailing rows that don't show up in the output. (Leading rows
- // unfortunately can't be ignored.)
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_Minus200_Minus200_100_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(-200, -200, 100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 0, 0)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 0, 0)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_Minus50_Minus50_100_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(-50, -50, 100, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 50, 50)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_Minus50_25_100_50)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(-50, 25, 100, 50),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 100, 50)),
- /* aOutputWriteRect = */ Some(IntRect(0, 25, 50, 50)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_25_Minus50_50_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(25, -50, 50, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 50, 100)),
- /* aOutputWriteRect = */ Some(IntRect(25, 0, 50, 50)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_50_25_100_50)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(50, 25, 100, 50),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 100, 50)),
- /* aOutputWriteRect = */ Some(IntRect(50, 25, 50, 50)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, WritePixels100_100_to_25_50_50_100)
-{
- WithRemoveFrameRectFilter(IntSize(100, 100),
- IntRect(25, 50, 50, 100),
- [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- // Note that aInputRect is 50x50 because RemoveFrameRectFilter ignores
- // trailing rows that don't show up in the output. (Leading rows
- // unfortunately can't be ignored.)
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aOutputWriteRect = */ Some(IntRect(25, 50, 50, 100)));
- });
-}
-
-TEST(ImageRemoveFrameRectFilter, RemoveFrameRectFailsFor0_0_to_0_0_100_100)
-{
- // A zero-size image is disallowed.
- AssertConfiguringRemoveFrameRectFilterFails(IntSize(0, 0),
- IntRect(0, 0, 100, 100));
-}
-
-TEST(ImageRemoveFrameRectFilter, RemoveFrameRectFailsForMinus1_Minus1_to_0_0_100_100)
-{
- // A negative-size image is disallowed.
- AssertConfiguringRemoveFrameRectFilterFails(IntSize(-1, -1),
- IntRect(0, 0, 100, 100));
-}
-
-TEST(ImageRemoveFrameRectFilter, RemoveFrameRectFailsFor100_100_to_0_0_0_0)
-{
- // A zero size frame rect is disallowed.
- AssertConfiguringRemoveFrameRectFilterFails(IntSize(100, 100),
- IntRect(0, 0, -1, -1));
-}
-
-TEST(ImageRemoveFrameRectFilter, RemoveFrameRectFailsFor100_100_to_0_0_Minus1_Minus1)
-{
- // A negative size frame rect is disallowed.
- AssertConfiguringRemoveFrameRectFilterFails(IntSize(100, 100),
- IntRect(0, 0, -1, -1));
-}
-
-TEST(ImageRemoveFrameRectFilter, ConfiguringPalettedRemoveFrameRectFails)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- // RemoveFrameRectFilter does not support paletted images, so configuration
- // should fail.
- AssertConfiguringPipelineFails(decoder,
- RemoveFrameRectConfig { IntRect(0, 0, 50, 50) },
- PalettedSurfaceConfig { decoder, IntSize(100, 100),
- IntRect(0, 0, 50, 50),
- SurfaceFormat::B8G8R8A8, 8,
- false });
-}
diff --git a/image/test/gtest/TestSourceBuffer.cpp b/image/test/gtest/TestSourceBuffer.cpp
deleted file mode 100644
index 05a88093f..000000000
--- a/image/test/gtest/TestSourceBuffer.cpp
+++ /dev/null
@@ -1,810 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include <algorithm>
-#include <cstdint>
-
-#include "mozilla/Move.h"
-#include "SourceBuffer.h"
-#include "SurfaceCache.h"
-
-using namespace mozilla;
-using namespace mozilla::image;
-
-using std::min;
-
-void
-ExpectChunkAndByteCount(const SourceBufferIterator& aIterator,
- uint32_t aChunks,
- size_t aBytes)
-{
- EXPECT_EQ(aChunks, aIterator.ChunkCount());
- EXPECT_EQ(aBytes, aIterator.ByteCount());
-}
-
-void
-ExpectRemainingBytes(const SourceBufferIterator& aIterator, size_t aBytes)
-{
- EXPECT_TRUE(aIterator.RemainingBytesIsNoMoreThan(aBytes));
- EXPECT_TRUE(aIterator.RemainingBytesIsNoMoreThan(aBytes + 1));
-
- if (aBytes > 0) {
- EXPECT_FALSE(aIterator.RemainingBytesIsNoMoreThan(0));
- EXPECT_FALSE(aIterator.RemainingBytesIsNoMoreThan(aBytes - 1));
- }
-}
-
-char
-GenerateByte(size_t aIndex)
-{
- uint8_t byte = aIndex % 256;
- return *reinterpret_cast<char*>(&byte);
-}
-
-void
-GenerateData(char* aOutput, size_t aOffset, size_t aLength)
-{
- for (size_t i = 0; i < aLength; ++i) {
- aOutput[i] = GenerateByte(aOffset + i);
- }
-}
-
-void
-GenerateData(char* aOutput, size_t aLength)
-{
- GenerateData(aOutput, 0, aLength);
-}
-
-void
-CheckData(const char* aData, size_t aOffset, size_t aLength)
-{
- for (size_t i = 0; i < aLength; ++i) {
- ASSERT_EQ(GenerateByte(aOffset + i), aData[i]);
- }
-}
-
-enum class AdvanceMode
-{
- eAdvanceAsMuchAsPossible,
- eAdvanceByLengthExactly
-};
-
-class ImageSourceBuffer : public ::testing::Test
-{
-public:
- ImageSourceBuffer()
- : mSourceBuffer(new SourceBuffer)
- , mExpectNoResume(new ExpectNoResume)
- , mCountResumes(new CountResumes)
- {
- GenerateData(mData, sizeof(mData));
- EXPECT_FALSE(mSourceBuffer->IsComplete());
- }
-
-protected:
- void CheckedAppendToBuffer(const char* aData, size_t aLength)
- {
- EXPECT_TRUE(NS_SUCCEEDED(mSourceBuffer->Append(aData, aLength)));
- }
-
- void CheckedAppendToBufferLastByteForLength(size_t aLength)
- {
- const char lastByte = GenerateByte(aLength);
- CheckedAppendToBuffer(&lastByte, 1);
- }
-
- void CheckedAppendToBufferInChunks(size_t aChunkLength, size_t aTotalLength)
- {
- char* data = new char[aChunkLength];
-
- size_t bytesWritten = 0;
- while (bytesWritten < aTotalLength) {
- GenerateData(data, bytesWritten, aChunkLength);
- size_t toWrite = min(aChunkLength, aTotalLength - bytesWritten);
- CheckedAppendToBuffer(data, toWrite);
- bytesWritten += toWrite;
- }
-
- delete[] data;
- }
-
- void CheckedCompleteBuffer(nsresult aCompletionStatus = NS_OK)
- {
- mSourceBuffer->Complete(aCompletionStatus);
- EXPECT_TRUE(mSourceBuffer->IsComplete());
- }
-
- void CheckedCompleteBuffer(SourceBufferIterator& aIterator,
- size_t aLength,
- nsresult aCompletionStatus = NS_OK)
- {
- CheckedCompleteBuffer(aCompletionStatus);
- ExpectRemainingBytes(aIterator, aLength);
- }
-
- void CheckedAdvanceIteratorStateOnly(SourceBufferIterator& aIterator,
- size_t aLength,
- uint32_t aChunks,
- size_t aTotalLength,
- AdvanceMode aAdvanceMode
- = AdvanceMode::eAdvanceAsMuchAsPossible)
- {
- const size_t advanceBy = aAdvanceMode == AdvanceMode::eAdvanceAsMuchAsPossible
- ? SIZE_MAX
- : aLength;
-
- auto state = aIterator.AdvanceOrScheduleResume(advanceBy, mExpectNoResume);
- ASSERT_EQ(SourceBufferIterator::READY, state);
- EXPECT_TRUE(aIterator.Data());
- EXPECT_EQ(aLength, aIterator.Length());
-
- ExpectChunkAndByteCount(aIterator, aChunks, aTotalLength);
- }
-
- void CheckedAdvanceIteratorStateOnly(SourceBufferIterator& aIterator,
- size_t aLength)
- {
- CheckedAdvanceIteratorStateOnly(aIterator, aLength, 1, aLength);
- }
-
- void CheckedAdvanceIterator(SourceBufferIterator& aIterator,
- size_t aLength,
- uint32_t aChunks,
- size_t aTotalLength,
- AdvanceMode aAdvanceMode
- = AdvanceMode::eAdvanceAsMuchAsPossible)
- {
- // Check that the iterator is in the expected state.
- CheckedAdvanceIteratorStateOnly(aIterator, aLength, aChunks,
- aTotalLength, aAdvanceMode);
-
- // Check that we read the expected data. To do this, we need to compute our
- // offset in the SourceBuffer, but fortunately that's pretty easy: it's the
- // total number of bytes the iterator has advanced through, minus the length
- // of the current chunk.
- const size_t offset = aIterator.ByteCount() - aIterator.Length();
- CheckData(aIterator.Data(), offset, aIterator.Length());
- }
-
- void CheckedAdvanceIterator(SourceBufferIterator& aIterator, size_t aLength)
- {
- CheckedAdvanceIterator(aIterator, aLength, 1, aLength);
- }
-
- void CheckIteratorMustWait(SourceBufferIterator& aIterator,
- IResumable* aOnResume)
- {
- auto state = aIterator.AdvanceOrScheduleResume(1, aOnResume);
- EXPECT_EQ(SourceBufferIterator::WAITING, state);
- }
-
- void CheckIteratorIsComplete(SourceBufferIterator& aIterator,
- uint32_t aChunks,
- size_t aTotalLength,
- nsresult aCompletionStatus = NS_OK)
- {
- ASSERT_TRUE(mSourceBuffer->IsComplete());
- auto state = aIterator.AdvanceOrScheduleResume(1, mExpectNoResume);
- ASSERT_EQ(SourceBufferIterator::COMPLETE, state);
- EXPECT_EQ(aCompletionStatus, aIterator.CompletionStatus());
- ExpectRemainingBytes(aIterator, 0);
- ExpectChunkAndByteCount(aIterator, aChunks, aTotalLength);
- }
-
- void CheckIteratorIsComplete(SourceBufferIterator& aIterator,
- size_t aTotalLength)
- {
- CheckIteratorIsComplete(aIterator, 1, aTotalLength);
- }
-
- AutoInitializeImageLib mInit;
- char mData[9];
- RefPtr<SourceBuffer> mSourceBuffer;
- RefPtr<ExpectNoResume> mExpectNoResume;
- RefPtr<CountResumes> mCountResumes;
-};
-
-TEST_F(ImageSourceBuffer, InitialState)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // RemainingBytesIsNoMoreThan() should always return false in the initial
- // state, since we can't know the answer until Complete() has been called.
- EXPECT_FALSE(iterator.RemainingBytesIsNoMoreThan(0));
- EXPECT_FALSE(iterator.RemainingBytesIsNoMoreThan(SIZE_MAX));
-
- // We haven't advanced our iterator at all, so its counters should be zero.
- ExpectChunkAndByteCount(iterator, 0, 0);
-
- // Attempt to advance; we should fail, and end up in the WAITING state. We
- // expect no resumes because we don't actually append anything to the
- // SourceBuffer in this test.
- CheckIteratorMustWait(iterator, mExpectNoResume);
-}
-
-TEST_F(ImageSourceBuffer, ZeroLengthBufferAlwaysFails)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Complete the buffer without writing to it, providing a successful
- // completion status.
- CheckedCompleteBuffer(iterator, 0);
-
- // Completing a buffer without writing to it results in an automatic failure;
- // make sure that the actual completion status we get from the iterator
- // reflects this.
- CheckIteratorIsComplete(iterator, 0, 0, NS_ERROR_FAILURE);
-}
-
-TEST_F(ImageSourceBuffer, CompleteSuccess)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write a single byte to the buffer and complete the buffer. (We have to
- // write at least one byte because completing a zero length buffer always
- // fails; see the ZeroLengthBufferAlwaysFails test.)
- CheckedAppendToBuffer(mData, 1);
- CheckedCompleteBuffer(iterator, 1);
-
- // We should be able to advance once (to read the single byte) and then should
- // reach the COMPLETE state with a successful status.
- CheckedAdvanceIterator(iterator, 1);
- CheckIteratorIsComplete(iterator, 1);
-}
-
-TEST_F(ImageSourceBuffer, CompleteFailure)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write a single byte to the buffer and complete the buffer. (We have to
- // write at least one byte because completing a zero length buffer always
- // fails; see the ZeroLengthBufferAlwaysFails test.)
- CheckedAppendToBuffer(mData, 1);
- CheckedCompleteBuffer(iterator, 1, NS_ERROR_FAILURE);
-
- // Advance the iterator. Because a failing status is propagated to the
- // iterator as soon as it advances, we won't be able to read the single byte
- // that we wrote above; we go directly into the COMPLETE state.
- CheckIteratorIsComplete(iterator, 0, 0, NS_ERROR_FAILURE);
-}
-
-TEST_F(ImageSourceBuffer, Append)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write test data to the buffer.
- EXPECT_TRUE(NS_SUCCEEDED(mSourceBuffer->ExpectLength(sizeof(mData))));
- CheckedAppendToBuffer(mData, sizeof(mData));
- CheckedCompleteBuffer(iterator, sizeof(mData));
-
- // Verify that we can read it back via the iterator, and that the final state
- // is what we expect.
- CheckedAdvanceIterator(iterator, sizeof(mData));
- CheckIteratorIsComplete(iterator, sizeof(mData));
-}
-
-TEST_F(ImageSourceBuffer, HugeAppendFails)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // We should fail to append anything bigger than what the SurfaceCache can
- // hold, so use the SurfaceCache's maximum capacity to calculate what a
- // "massive amount of data" (see below) consists of on this platform.
- ASSERT_LT(SurfaceCache::MaximumCapacity(), SIZE_MAX);
- const size_t hugeSize = SurfaceCache::MaximumCapacity() + 1;
-
- // Attempt to write a massive amount of data and verify that it fails. (We'd
- // get a buffer overrun during the test if it succeeds, but if it succeeds
- // that's the least of our problems.)
- EXPECT_TRUE(NS_FAILED(mSourceBuffer->Append(mData, hugeSize)));
- EXPECT_TRUE(mSourceBuffer->IsComplete());
- CheckIteratorIsComplete(iterator, 0, 0, NS_ERROR_OUT_OF_MEMORY);
-}
-
-TEST_F(ImageSourceBuffer, AppendFromInputStream)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Construct an input stream with some arbitrary data. (We use test data from
- // one of the decoder tests.)
- nsCOMPtr<nsIInputStream> inputStream = LoadFile(GreenPNGTestCase().mPath);
- ASSERT_TRUE(inputStream != nullptr);
-
- // Figure out how much data we have.
- uint64_t length;
- ASSERT_TRUE(NS_SUCCEEDED(inputStream->Available(&length)));
-
- // Write test data to the buffer.
- EXPECT_TRUE(NS_SUCCEEDED(mSourceBuffer->AppendFromInputStream(inputStream,
- length)));
- CheckedCompleteBuffer(iterator, length);
-
- // Verify that the iterator sees the appropriate amount of data.
- CheckedAdvanceIteratorStateOnly(iterator, length);
- CheckIteratorIsComplete(iterator, length);
-}
-
-TEST_F(ImageSourceBuffer, AppendAfterComplete)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write test data to the buffer.
- EXPECT_TRUE(NS_SUCCEEDED(mSourceBuffer->ExpectLength(sizeof(mData))));
- CheckedAppendToBuffer(mData, sizeof(mData));
- CheckedCompleteBuffer(iterator, sizeof(mData));
-
- // Verify that we can read it back via the iterator, and that the final state
- // is what we expect.
- CheckedAdvanceIterator(iterator, sizeof(mData));
- CheckIteratorIsComplete(iterator, sizeof(mData));
-
- // Write more data to the completed buffer.
- EXPECT_TRUE(NS_FAILED(mSourceBuffer->Append(mData, sizeof(mData))));
-
- // Try to read with a new iterator and verify that the new data got ignored.
- SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
- CheckedAdvanceIterator(iterator2, sizeof(mData));
- CheckIteratorIsComplete(iterator2, sizeof(mData));
-}
-
-TEST_F(ImageSourceBuffer, MinChunkCapacity)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write test data to the buffer using many small appends. Since
- // ExpectLength() isn't being called, we should be able to write up to
- // SourceBuffer::MIN_CHUNK_CAPACITY bytes without a second chunk being
- // allocated.
- CheckedAppendToBufferInChunks(10, SourceBuffer::MIN_CHUNK_CAPACITY);
-
- // Verify that the iterator sees the appropriate amount of data.
- CheckedAdvanceIterator(iterator, SourceBuffer::MIN_CHUNK_CAPACITY);
-
- // Write one more byte; we expect to see that it triggers an allocation.
- CheckedAppendToBufferLastByteForLength(SourceBuffer::MIN_CHUNK_CAPACITY);
- CheckedCompleteBuffer(iterator, 1);
-
- // Verify that the iterator sees the new byte and a new chunk has been
- // allocated.
- CheckedAdvanceIterator(iterator, 1, 2, SourceBuffer::MIN_CHUNK_CAPACITY + 1);
- CheckIteratorIsComplete(iterator, 2, SourceBuffer::MIN_CHUNK_CAPACITY + 1);
-}
-
-TEST_F(ImageSourceBuffer, ExpectLengthDoesNotShrinkBelowMinCapacity)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the buffer,
- // but call ExpectLength() first to make SourceBuffer expect only a single
- // byte. We expect this to still result in only one chunk, because
- // regardless of ExpectLength() we won't allocate a chunk smaller than
- // MIN_CHUNK_CAPACITY bytes.
- EXPECT_TRUE(NS_SUCCEEDED(mSourceBuffer->ExpectLength(1)));
- CheckedAppendToBufferInChunks(10, SourceBuffer::MIN_CHUNK_CAPACITY);
- CheckedCompleteBuffer(iterator, SourceBuffer::MIN_CHUNK_CAPACITY);
-
- // Verify that the iterator sees a single chunk.
- CheckedAdvanceIterator(iterator, SourceBuffer::MIN_CHUNK_CAPACITY);
- CheckIteratorIsComplete(iterator, 1, SourceBuffer::MIN_CHUNK_CAPACITY);
-}
-
-TEST_F(ImageSourceBuffer, ExpectLengthGrowsAboveMinCapacity)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write two times SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
- // buffer, calling ExpectLength() with the correct length first. We expect
- // this to result in only one chunk, because ExpectLength() allows us to
- // allocate a larger first chunk than MIN_CHUNK_CAPACITY bytes.
- const size_t length = 2 * SourceBuffer::MIN_CHUNK_CAPACITY;
- EXPECT_TRUE(NS_SUCCEEDED(mSourceBuffer->ExpectLength(length)));
- CheckedAppendToBufferInChunks(10, length);
-
- // Verify that the iterator sees a single chunk.
- CheckedAdvanceIterator(iterator, length);
-
- // Write one more byte; we expect to see that it triggers an allocation.
- CheckedAppendToBufferLastByteForLength(length);
- CheckedCompleteBuffer(iterator, 1);
-
- // Verify that the iterator sees the new byte and a new chunk has been
- // allocated.
- CheckedAdvanceIterator(iterator, 1, 2, length + 1);
- CheckIteratorIsComplete(iterator, 2, length + 1);
-}
-
-TEST_F(ImageSourceBuffer, HugeExpectLengthFails)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // ExpectLength() should fail if the length is bigger than what the
- // SurfaceCache can hold, so use the SurfaceCache's maximum capacity to
- // calculate what a "massive amount of data" (see below) consists of on this
- // platform.
- ASSERT_LT(SurfaceCache::MaximumCapacity(), SIZE_MAX);
- const size_t hugeSize = SurfaceCache::MaximumCapacity() + 1;
-
- // Attempt to write a massive amount of data and verify that it fails. (We'd
- // get a buffer overrun during the test if it succeeds, but if it succeeds
- // that's the least of our problems.)
- EXPECT_TRUE(NS_FAILED(mSourceBuffer->ExpectLength(hugeSize)));
- EXPECT_TRUE(mSourceBuffer->IsComplete());
- CheckIteratorIsComplete(iterator, 0, 0, NS_ERROR_OUT_OF_MEMORY);
-}
-
-TEST_F(ImageSourceBuffer, LargeAppendsAllocateOnlyOneChunk)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write two times SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
- // buffer in a single Append() call. We expect this to result in only one
- // chunk even though ExpectLength() wasn't called, because we should always
- // allocate a new chunk large enough to store the data we have at hand.
- constexpr size_t length = 2 * SourceBuffer::MIN_CHUNK_CAPACITY;
- char data[length];
- GenerateData(data, sizeof(data));
- CheckedAppendToBuffer(data, length);
-
- // Verify that the iterator sees a single chunk.
- CheckedAdvanceIterator(iterator, length);
-
- // Write one more byte; we expect to see that it triggers an allocation.
- CheckedAppendToBufferLastByteForLength(length);
- CheckedCompleteBuffer(iterator, 1);
-
- // Verify that the iterator sees the new byte and a new chunk has been
- // allocated.
- CheckedAdvanceIterator(iterator, 1, 2, length + 1);
- CheckIteratorIsComplete(iterator, 2, length + 1);
-}
-
-TEST_F(ImageSourceBuffer, LargeAppendsAllocateAtMostOneChunk)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Allocate some data we'll use below.
- constexpr size_t firstWriteLength = SourceBuffer::MIN_CHUNK_CAPACITY / 2;
- constexpr size_t secondWriteLength = 3 * SourceBuffer::MIN_CHUNK_CAPACITY;
- constexpr size_t totalLength = firstWriteLength + secondWriteLength;
- char data[totalLength];
- GenerateData(data, sizeof(data));
-
- // Write half of SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
- // buffer in a single Append() call. This should fill half of the first chunk.
- CheckedAppendToBuffer(data, firstWriteLength);
-
- // Write three times SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
- // buffer in a single Append() call. We expect this to result in the first of
- // the first chunk being filled and a new chunk being allocated for the
- // remainder.
- CheckedAppendToBuffer(data + firstWriteLength, secondWriteLength);
-
- // Verify that the iterator sees a MIN_CHUNK_CAPACITY-length chunk.
- CheckedAdvanceIterator(iterator, SourceBuffer::MIN_CHUNK_CAPACITY);
-
- // Verify that the iterator sees a second chunk of the length we expect.
- const size_t expectedSecondChunkLength =
- totalLength - SourceBuffer::MIN_CHUNK_CAPACITY;
- CheckedAdvanceIterator(iterator, expectedSecondChunkLength, 2, totalLength);
-
- // Write one more byte; we expect to see that it triggers an allocation.
- CheckedAppendToBufferLastByteForLength(totalLength);
- CheckedCompleteBuffer(iterator, 1);
-
- // Verify that the iterator sees the new byte and a new chunk has been
- // allocated.
- CheckedAdvanceIterator(iterator, 1, 3, totalLength + 1);
- CheckIteratorIsComplete(iterator, 3, totalLength + 1);
-}
-
-TEST_F(ImageSourceBuffer, CompactionHappensWhenBufferIsComplete)
-{
- constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
- constexpr size_t totalLength = 2 * chunkLength;
-
- // Write enough data to create two chunks.
- CheckedAppendToBufferInChunks(chunkLength, totalLength);
-
- {
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Verify that the iterator sees two chunks.
- CheckedAdvanceIterator(iterator, chunkLength);
- CheckedAdvanceIterator(iterator, chunkLength, 2, totalLength);
- }
-
- // Complete the buffer, which should trigger compaction implicitly.
- CheckedCompleteBuffer();
-
- {
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Verify that compaction happened and there's now only one chunk.
- CheckedAdvanceIterator(iterator, totalLength);
- CheckIteratorIsComplete(iterator, 1, totalLength);
- }
-}
-
-TEST_F(ImageSourceBuffer, CompactionIsDelayedWhileIteratorsExist)
-{
- constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
- constexpr size_t totalLength = 2 * chunkLength;
-
- {
- SourceBufferIterator outerIterator = mSourceBuffer->Iterator();
-
- {
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Write enough data to create two chunks.
- CheckedAppendToBufferInChunks(chunkLength, totalLength);
- CheckedCompleteBuffer(iterator, totalLength);
-
- // Verify that the iterator sees two chunks. Since there are live
- // iterators, compaction shouldn't have happened when we completed the
- // buffer.
- CheckedAdvanceIterator(iterator, chunkLength);
- CheckedAdvanceIterator(iterator, chunkLength, 2, totalLength);
- CheckIteratorIsComplete(iterator, 2, totalLength);
- }
-
- // Now |iterator| has been destroyed, but |outerIterator| still exists, so
- // we expect no compaction to have occurred at this point.
- CheckedAdvanceIterator(outerIterator, chunkLength);
- CheckedAdvanceIterator(outerIterator, chunkLength, 2, totalLength);
- CheckIteratorIsComplete(outerIterator, 2, totalLength);
- }
-
- // Now all iterators have been destroyed. Since the buffer was already
- // complete, we expect compaction to happen implicitly here.
-
- {
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Verify that compaction happened and there's now only one chunk.
- CheckedAdvanceIterator(iterator, totalLength);
- CheckIteratorIsComplete(iterator, 1, totalLength);
- }
-}
-
-TEST_F(ImageSourceBuffer, SourceBufferIteratorsCanBeMoved)
-{
- constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
- constexpr size_t totalLength = 2 * chunkLength;
-
- // Write enough data to create two chunks. We create an iterator here to make
- // sure that compaction doesn't happen during the test.
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
- CheckedAppendToBufferInChunks(chunkLength, totalLength);
- CheckedCompleteBuffer(iterator, totalLength);
-
- auto GetIterator = [&]{
- SourceBufferIterator lambdaIterator = mSourceBuffer->Iterator();
- CheckedAdvanceIterator(lambdaIterator, chunkLength);
- return lambdaIterator;
- };
-
- // Move-construct |movedIterator| from the iterator returned from
- // GetIterator() and check that its state is as we expect.
- SourceBufferIterator movedIterator = Move(GetIterator());
- EXPECT_TRUE(movedIterator.Data());
- EXPECT_EQ(chunkLength, movedIterator.Length());
- ExpectChunkAndByteCount(movedIterator, 1, chunkLength);
-
- // Make sure that we can advance the iterator.
- CheckedAdvanceIterator(movedIterator, chunkLength, 2, totalLength);
-
- // Make sure that the iterator handles completion properly.
- CheckIteratorIsComplete(movedIterator, 2, totalLength);
-
- // Move-assign |movedIterator| from the iterator returned from
- // GetIterator() and check that its state is as we expect.
- movedIterator = Move(GetIterator());
- EXPECT_TRUE(movedIterator.Data());
- EXPECT_EQ(chunkLength, movedIterator.Length());
- ExpectChunkAndByteCount(movedIterator, 1, chunkLength);
-
- // Make sure that we can advance the iterator.
- CheckedAdvanceIterator(movedIterator, chunkLength, 2, totalLength);
-
- // Make sure that the iterator handles completion properly.
- CheckIteratorIsComplete(movedIterator, 2, totalLength);
-}
-
-TEST_F(ImageSourceBuffer, SubchunkAdvance)
-{
- constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
- constexpr size_t totalLength = 2 * chunkLength;
-
- // Write enough data to create two chunks. We create our iterator here to make
- // sure that compaction doesn't happen during the test.
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
- CheckedAppendToBufferInChunks(chunkLength, totalLength);
- CheckedCompleteBuffer(iterator, totalLength);
-
- // Advance through the first chunk. The chunk count should not increase.
- // We check that by always passing 1 for the |aChunks| parameter of
- // CheckedAdvanceIteratorStateOnly(). We have to call CheckData() manually
- // because the offset calculation in CheckedAdvanceIterator() assumes that
- // we're advancing a chunk at a time.
- size_t offset = 0;
- while (offset < chunkLength) {
- CheckedAdvanceIteratorStateOnly(iterator, 1, 1, chunkLength,
- AdvanceMode::eAdvanceByLengthExactly);
- CheckData(iterator.Data(), offset++, iterator.Length());
- }
-
- // Read the first byte of the second chunk. This is the point at which we
- // can't advance within the same chunk, so the chunk count should increase. We
- // check that by passing 2 for the |aChunks| parameter of
- // CheckedAdvanceIteratorStateOnly().
- CheckedAdvanceIteratorStateOnly(iterator, 1, 2, totalLength,
- AdvanceMode::eAdvanceByLengthExactly);
- CheckData(iterator.Data(), offset++, iterator.Length());
-
- // Read the rest of the second chunk. The chunk count should not increase.
- while (offset < totalLength) {
- CheckedAdvanceIteratorStateOnly(iterator, 1, 2, totalLength,
- AdvanceMode::eAdvanceByLengthExactly);
- CheckData(iterator.Data(), offset++, iterator.Length());
- }
-
- // Make sure we reached the end.
- CheckIteratorIsComplete(iterator, 2, totalLength);
-}
-
-TEST_F(ImageSourceBuffer, SubchunkZeroByteAdvance)
-{
- constexpr size_t chunkLength = SourceBuffer::MIN_CHUNK_CAPACITY;
- constexpr size_t totalLength = 2 * chunkLength;
-
- // Write enough data to create two chunks. We create our iterator here to make
- // sure that compaction doesn't happen during the test.
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
- CheckedAppendToBufferInChunks(chunkLength, totalLength);
- CheckedCompleteBuffer(iterator, totalLength);
-
- // Make an initial zero-length advance. Although a zero-length advance
- // normally won't cause us to read a chunk from the SourceBuffer, we'll do so
- // if the iterator is in the initial state to keep the invariant that
- // SourceBufferIterator in the READY state always returns a non-null pointer
- // from Data().
- CheckedAdvanceIteratorStateOnly(iterator, 0, 1, chunkLength,
- AdvanceMode::eAdvanceByLengthExactly);
-
- // Advance through the first chunk. As in the |SubchunkAdvance| test, the
- // chunk count should not increase. We do a zero-length advance after each
- // normal advance to ensure that zero-length advances do not change the
- // iterator's position or cause a new chunk to be read.
- size_t offset = 0;
- while (offset < chunkLength) {
- CheckedAdvanceIteratorStateOnly(iterator, 1, 1, chunkLength,
- AdvanceMode::eAdvanceByLengthExactly);
- CheckData(iterator.Data(), offset++, iterator.Length());
- CheckedAdvanceIteratorStateOnly(iterator, 0, 1, chunkLength,
- AdvanceMode::eAdvanceByLengthExactly);
- }
-
- // Read the first byte of the second chunk. This is the point at which we
- // can't advance within the same chunk, so the chunk count should increase. As
- // before, we do a zero-length advance afterward.
- CheckedAdvanceIteratorStateOnly(iterator, 1, 2, totalLength,
- AdvanceMode::eAdvanceByLengthExactly);
- CheckData(iterator.Data(), offset++, iterator.Length());
- CheckedAdvanceIteratorStateOnly(iterator, 0, 2, totalLength,
- AdvanceMode::eAdvanceByLengthExactly);
-
- // Read the rest of the second chunk. The chunk count should not increase. As
- // before, we do a zero-length advance after each normal advance.
- while (offset < totalLength) {
- CheckedAdvanceIteratorStateOnly(iterator, 1, 2, totalLength,
- AdvanceMode::eAdvanceByLengthExactly);
- CheckData(iterator.Data(), offset++, iterator.Length());
- CheckedAdvanceIteratorStateOnly(iterator, 0, 2, totalLength,
- AdvanceMode::eAdvanceByLengthExactly);
- }
-
- // Make sure we reached the end.
- CheckIteratorIsComplete(iterator, 2, totalLength);
-}
-
-TEST_F(ImageSourceBuffer, SubchunkZeroByteAdvanceWithNoData)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Check that advancing by zero bytes still makes us enter the WAITING state.
- // This is because if we entered the READY state before reading any data at
- // all, we'd break the invariant that SourceBufferIterator::Data() always
- // returns a non-null pointer in the READY state.
- auto state = iterator.AdvanceOrScheduleResume(0, mCountResumes);
- EXPECT_EQ(SourceBufferIterator::WAITING, state);
-
- // Call Complete(). This should trigger a resume.
- CheckedCompleteBuffer();
- EXPECT_EQ(1u, mCountResumes->Count());
-}
-
-TEST_F(ImageSourceBuffer, NullIResumable)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Check that we can't advance.
- CheckIteratorMustWait(iterator, nullptr);
-
- // Append to the buffer, which would cause a resume if we had passed a
- // non-null IResumable.
- CheckedAppendToBuffer(mData, sizeof(mData));
- CheckedCompleteBuffer(iterator, sizeof(mData));
-}
-
-TEST_F(ImageSourceBuffer, AppendTriggersResume)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Check that we can't advance.
- CheckIteratorMustWait(iterator, mCountResumes);
-
- // Call Append(). This should trigger a resume.
- mSourceBuffer->Append(mData, sizeof(mData));
- EXPECT_EQ(1u, mCountResumes->Count());
-}
-
-TEST_F(ImageSourceBuffer, OnlyOneResumeTriggeredPerAppend)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Check that we can't advance.
- CheckIteratorMustWait(iterator, mCountResumes);
-
- // Allocate some data we'll use below.
- constexpr size_t firstWriteLength = SourceBuffer::MIN_CHUNK_CAPACITY / 2;
- constexpr size_t secondWriteLength = 3 * SourceBuffer::MIN_CHUNK_CAPACITY;
- constexpr size_t totalLength = firstWriteLength + secondWriteLength;
- char data[totalLength];
- GenerateData(data, sizeof(data));
-
- // Write half of SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
- // buffer in a single Append() call. This should fill half of the first chunk.
- // This should trigger a resume.
- CheckedAppendToBuffer(data, firstWriteLength);
- EXPECT_EQ(1u, mCountResumes->Count());
-
- // Advance past the new data and wait again.
- CheckedAdvanceIterator(iterator, firstWriteLength);
- CheckIteratorMustWait(iterator, mCountResumes);
-
- // Write three times SourceBuffer::MIN_CHUNK_CAPACITY bytes of test data to the
- // buffer in a single Append() call. We expect this to result in the first of
- // the first chunk being filled and a new chunk being allocated for the
- // remainder. Even though two chunks are getting written to here, only *one*
- // resume should get triggered, for a total of two in this test.
- CheckedAppendToBuffer(data + firstWriteLength, secondWriteLength);
- EXPECT_EQ(2u, mCountResumes->Count());
-}
-
-TEST_F(ImageSourceBuffer, CompleteTriggersResume)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Check that we can't advance.
- CheckIteratorMustWait(iterator, mCountResumes);
-
- // Call Complete(). This should trigger a resume.
- CheckedCompleteBuffer();
- EXPECT_EQ(1u, mCountResumes->Count());
-}
-
-TEST_F(ImageSourceBuffer, ExpectLengthDoesNotTriggerResume)
-{
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
-
- // Check that we can't advance.
- CheckIteratorMustWait(iterator, mExpectNoResume);
-
- // Call ExpectLength(). If this triggers a resume, |mExpectNoResume| will
- // ensure that the test fails.
- mSourceBuffer->ExpectLength(1000);
-}
diff --git a/image/test/gtest/TestStreamingLexer.cpp b/image/test/gtest/TestStreamingLexer.cpp
deleted file mode 100644
index 590b10e81..000000000
--- a/image/test/gtest/TestStreamingLexer.cpp
+++ /dev/null
@@ -1,973 +0,0 @@
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "mozilla/Vector.h"
-#include "StreamingLexer.h"
-
-using namespace mozilla;
-using namespace mozilla::image;
-
-enum class TestState
-{
- ONE,
- TWO,
- THREE,
- UNBUFFERED,
- TRUNCATED_SUCCESS,
- TRUNCATED_FAILURE
-};
-
-void
-CheckLexedData(const char* aData,
- size_t aLength,
- size_t aOffset,
- size_t aExpectedLength)
-{
- EXPECT_TRUE(aLength == aExpectedLength);
-
- for (size_t i = 0; i < aLength; ++i) {
- EXPECT_EQ(aData[i], char(aOffset + i + 1));
- }
-}
-
-LexerTransition<TestState>
-DoLex(TestState aState, const char* aData, size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- CheckLexedData(aData, aLength, 0, 3);
- return Transition::To(TestState::TWO, 3);
- case TestState::TWO:
- CheckLexedData(aData, aLength, 3, 3);
- return Transition::To(TestState::THREE, 3);
- case TestState::THREE:
- CheckLexedData(aData, aLength, 6, 3);
- return Transition::TerminateSuccess();
- case TestState::TRUNCATED_SUCCESS:
- return Transition::TerminateSuccess();
- case TestState::TRUNCATED_FAILURE:
- return Transition::TerminateFailure();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithUnbuffered(TestState aState, const char* aData, size_t aLength,
- Vector<char>& aUnbufferedVector)
-{
- switch (aState) {
- case TestState::ONE:
- CheckLexedData(aData, aLength, 0, 3);
- return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
- case TestState::TWO:
- CheckLexedData(aUnbufferedVector.begin(), aUnbufferedVector.length(), 3, 3);
- return Transition::To(TestState::THREE, 3);
- case TestState::THREE:
- CheckLexedData(aData, aLength, 6, 3);
- return Transition::TerminateSuccess();
- case TestState::UNBUFFERED:
- EXPECT_TRUE(aLength <= 3);
- EXPECT_TRUE(aUnbufferedVector.append(aData, aLength));
- return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithUnbufferedTerminate(TestState aState, const char* aData, size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- CheckLexedData(aData, aLength, 0, 3);
- return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
- case TestState::UNBUFFERED:
- return Transition::TerminateSuccess();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithYield(TestState aState, const char* aData, size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- CheckLexedData(aData, aLength, 0, 3);
- return Transition::ToAfterYield(TestState::TWO);
- case TestState::TWO:
- CheckLexedData(aData, aLength, 0, 3);
- return Transition::To(TestState::THREE, 6);
- case TestState::THREE:
- CheckLexedData(aData, aLength, 3, 6);
- return Transition::TerminateSuccess();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithTerminateAfterYield(TestState aState, const char* aData, size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- CheckLexedData(aData, aLength, 0, 3);
- return Transition::ToAfterYield(TestState::TWO);
- case TestState::TWO:
- return Transition::TerminateSuccess();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithZeroLengthStates(TestState aState, const char* aData, size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- EXPECT_TRUE(aLength == 0);
- return Transition::To(TestState::TWO, 0);
- case TestState::TWO:
- EXPECT_TRUE(aLength == 0);
- return Transition::To(TestState::THREE, 9);
- case TestState::THREE:
- CheckLexedData(aData, aLength, 0, 9);
- return Transition::TerminateSuccess();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithZeroLengthStatesAtEnd(TestState aState, const char* aData, size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- CheckLexedData(aData, aLength, 0, 9);
- return Transition::To(TestState::TWO, 0);
- case TestState::TWO:
- EXPECT_TRUE(aLength == 0);
- return Transition::To(TestState::THREE, 0);
- case TestState::THREE:
- EXPECT_TRUE(aLength == 0);
- return Transition::TerminateSuccess();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithZeroLengthYield(TestState aState, const char* aData, size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- EXPECT_EQ(0u, aLength);
- return Transition::ToAfterYield(TestState::TWO);
- case TestState::TWO:
- EXPECT_EQ(0u, aLength);
- return Transition::To(TestState::THREE, 9);
- case TestState::THREE:
- CheckLexedData(aData, aLength, 0, 9);
- return Transition::TerminateSuccess();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithZeroLengthStatesUnbuffered(TestState aState,
- const char* aData,
- size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- EXPECT_TRUE(aLength == 0);
- return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 0);
- case TestState::TWO:
- EXPECT_TRUE(aLength == 0);
- return Transition::To(TestState::THREE, 9);
- case TestState::THREE:
- CheckLexedData(aData, aLength, 0, 9);
- return Transition::TerminateSuccess();
- case TestState::UNBUFFERED:
- ADD_FAILURE() << "Should not enter zero-length unbuffered state";
- return Transition::TerminateFailure();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-LexerTransition<TestState>
-DoLexWithZeroLengthStatesAfterUnbuffered(TestState aState,
- const char* aData,
- size_t aLength)
-{
- switch (aState) {
- case TestState::ONE:
- EXPECT_TRUE(aLength == 0);
- return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 9);
- case TestState::TWO:
- EXPECT_TRUE(aLength == 0);
- return Transition::To(TestState::THREE, 0);
- case TestState::THREE:
- EXPECT_TRUE(aLength == 0);
- return Transition::TerminateSuccess();
- case TestState::UNBUFFERED:
- CheckLexedData(aData, aLength, 0, 9);
- return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
-}
-
-class ImageStreamingLexer : public ::testing::Test
-{
-public:
- // Note that mLexer is configured to enter TerminalState::FAILURE immediately
- // if the input data is truncated. We don't expect that to happen in most
- // tests, so we want to detect that issue. If a test needs a different
- // behavior, we create a special StreamingLexer just for that test.
- ImageStreamingLexer()
- : mLexer(Transition::To(TestState::ONE, 3), Transition::TerminateFailure())
- , mSourceBuffer(new SourceBuffer)
- , mIterator(mSourceBuffer->Iterator())
- , mExpectNoResume(new ExpectNoResume)
- , mCountResumes(new CountResumes)
- { }
-
-protected:
- void CheckTruncatedState(StreamingLexer<TestState>& aLexer,
- TerminalState aExpectedTerminalState,
- nsresult aCompletionStatus = NS_OK)
- {
- for (unsigned i = 0; i < 9; ++i) {
- if (i < 2) {
- mSourceBuffer->Append(mData + i, 1);
- } else if (i == 2) {
- mSourceBuffer->Complete(aCompletionStatus);
- }
-
- LexerResult result = aLexer.Lex(mIterator, mCountResumes, DoLex);
-
- if (i >= 2) {
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(aExpectedTerminalState, result.as<TerminalState>());
- } else {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- EXPECT_EQ(2u, mCountResumes->Count());
- }
-
- AutoInitializeImageLib mInit;
- const char mData[9] { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
- StreamingLexer<TestState> mLexer;
- RefPtr<SourceBuffer> mSourceBuffer;
- SourceBufferIterator mIterator;
- RefPtr<ExpectNoResume> mExpectNoResume;
- RefPtr<CountResumes> mCountResumes;
-};
-
-TEST_F(ImageStreamingLexer, ZeroLengthData)
-{
- // Test a zero-length input.
- mSourceBuffer->Complete(NS_OK);
-
- LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
-
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, ZeroLengthDataUnbuffered)
-{
- // Test a zero-length input.
- mSourceBuffer->Complete(NS_OK);
-
- // Create a special StreamingLexer for this test because we want the first
- // state to be unbuffered.
- StreamingLexer<TestState> lexer(Transition::ToUnbuffered(TestState::ONE,
- TestState::UNBUFFERED,
- sizeof(mData)),
- Transition::TerminateFailure());
-
- LexerResult result = lexer.Lex(mIterator, mExpectNoResume, DoLex);
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, StartWithTerminal)
-{
- // Create a special StreamingLexer for this test because we want the first
- // state to be a terminal state. This doesn't really make sense, but we should
- // handle it.
- StreamingLexer<TestState> lexer(Transition::TerminateSuccess(),
- Transition::TerminateFailure());
- LexerResult result = lexer.Lex(mIterator, mExpectNoResume, DoLex);
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, SingleChunk)
-{
- // Test delivering all the data at once.
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
-
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, SingleChunkWithUnbuffered)
-{
- Vector<char> unbufferedVector;
-
- // Test delivering all the data at once.
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- LexerResult result =
- mLexer.Lex(mIterator, mExpectNoResume,
- [&](TestState aState, const char* aData, size_t aLength) {
- return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
- });
-
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, SingleChunkWithYield)
-{
- // Test delivering all the data at once.
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLexWithYield);
- ASSERT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
-
- result = mLexer.Lex(mIterator, mExpectNoResume, DoLexWithYield);
- ASSERT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, ChunkPerState)
-{
- // Test delivering in perfectly-sized chunks, one per state.
- for (unsigned i = 0; i < 3; ++i) {
- mSourceBuffer->Append(mData + 3 * i, 3);
- LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);
-
- if (i == 2) {
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- } else {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- EXPECT_EQ(2u, mCountResumes->Count());
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, ChunkPerStateWithUnbuffered)
-{
- Vector<char> unbufferedVector;
-
- // Test delivering in perfectly-sized chunks, one per state.
- for (unsigned i = 0; i < 3; ++i) {
- mSourceBuffer->Append(mData + 3 * i, 3);
- LexerResult result =
- mLexer.Lex(mIterator, mCountResumes,
- [&](TestState aState, const char* aData, size_t aLength) {
- return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
- });
-
- if (i == 2) {
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- } else {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- EXPECT_EQ(2u, mCountResumes->Count());
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, ChunkPerStateWithYield)
-{
- // Test delivering in perfectly-sized chunks, one per state.
- mSourceBuffer->Append(mData, 3);
- LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
-
- result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
-
- mSourceBuffer->Append(mData + 3, 6);
- result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-
- EXPECT_EQ(1u, mCountResumes->Count());
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, ChunkPerStateWithUnbufferedYield)
-{
- size_t unbufferedCallCount = 0;
- Vector<char> unbufferedVector;
- auto lexerFunc = [&](TestState aState, const char* aData, size_t aLength)
- -> LexerTransition<TestState> {
- switch (aState) {
- case TestState::ONE:
- CheckLexedData(aData, aLength, 0, 3);
- return Transition::ToUnbuffered(TestState::TWO, TestState::UNBUFFERED, 3);
- case TestState::TWO:
- CheckLexedData(unbufferedVector.begin(), unbufferedVector.length(), 3, 3);
- return Transition::To(TestState::THREE, 3);
- case TestState::THREE:
- CheckLexedData(aData, aLength, 6, 3);
- return Transition::TerminateSuccess();
- case TestState::UNBUFFERED:
- switch (unbufferedCallCount) {
- case 0:
- CheckLexedData(aData, aLength, 3, 3);
- EXPECT_TRUE(unbufferedVector.append(aData, 2));
- unbufferedCallCount++;
-
- // Continue after yield, telling StreamingLexer we consumed 2 bytes.
- return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 2);
-
- case 1:
- CheckLexedData(aData, aLength, 5, 1);
- EXPECT_TRUE(unbufferedVector.append(aData, 1));
- unbufferedCallCount++;
-
- // Continue after yield, telling StreamingLexer we consumed 1 byte.
- // We should end up in the TWO state.
- return Transition::ContinueUnbuffered(TestState::UNBUFFERED);
- }
- ADD_FAILURE() << "Too many invocations of TestState::UNBUFFERED";
- return Transition::TerminateFailure();
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
- };
-
- // Test delivering in perfectly-sized chunks, one per state.
- for (unsigned i = 0; i < 3; ++i) {
- mSourceBuffer->Append(mData + 3 * i, 3);
- LexerResult result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);
-
- switch (i) {
- case 0:
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- EXPECT_EQ(0u, unbufferedCallCount);
- break;
-
- case 1:
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
- EXPECT_EQ(1u, unbufferedCallCount);
-
- result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- EXPECT_EQ(2u, unbufferedCallCount);
- break;
-
- case 2:
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- break;
- }
- }
-
- EXPECT_EQ(2u, mCountResumes->Count());
- mSourceBuffer->Complete(NS_OK);
-
- LexerResult result = mLexer.Lex(mIterator, mCountResumes, lexerFunc);
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, OneByteChunks)
-{
- // Test delivering in one byte chunks.
- for (unsigned i = 0; i < 9; ++i) {
- mSourceBuffer->Append(mData + i, 1);
- LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLex);
-
- if (i == 8) {
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- } else {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- EXPECT_EQ(8u, mCountResumes->Count());
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, OneByteChunksWithUnbuffered)
-{
- Vector<char> unbufferedVector;
-
- // Test delivering in one byte chunks.
- for (unsigned i = 0; i < 9; ++i) {
- mSourceBuffer->Append(mData + i, 1);
- LexerResult result =
- mLexer.Lex(mIterator, mCountResumes,
- [&](TestState aState, const char* aData, size_t aLength) {
- return DoLexWithUnbuffered(aState, aData, aLength, unbufferedVector);
- });
-
- if (i == 8) {
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- } else {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- EXPECT_EQ(8u, mCountResumes->Count());
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, OneByteChunksWithYield)
-{
- // Test delivering in one byte chunks.
- for (unsigned i = 0; i < 9; ++i) {
- mSourceBuffer->Append(mData + i, 1);
- LexerResult result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
-
- switch (i) {
- case 2:
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
-
- result = mLexer.Lex(mIterator, mCountResumes, DoLexWithYield);
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- break;
-
- case 8:
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- break;
-
- default:
- EXPECT_TRUE(i < 9);
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- EXPECT_EQ(8u, mCountResumes->Count());
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, ZeroLengthState)
-{
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- // Create a special StreamingLexer for this test because we want the first
- // state to be zero length.
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
- Transition::TerminateFailure());
-
- LexerResult result =
- lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStates);
-
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, ZeroLengthStatesAtEnd)
-{
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- // Create a special StreamingLexer for this test because we want the first
- // state to consume the full input.
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 9),
- Transition::TerminateFailure());
-
- LexerResult result =
- lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStatesAtEnd);
-
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, ZeroLengthStateWithYield)
-{
- // Create a special StreamingLexer for this test because we want the first
- // state to be zero length.
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
- Transition::TerminateFailure());
-
- mSourceBuffer->Append(mData, 3);
- LexerResult result =
- lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthYield);
- ASSERT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
-
- result = lexer.Lex(mIterator, mCountResumes, DoLexWithZeroLengthYield);
- ASSERT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
-
- mSourceBuffer->Append(mData + 3, sizeof(mData) - 3);
- mSourceBuffer->Complete(NS_OK);
- result = lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthYield);
- ASSERT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- EXPECT_EQ(1u, mCountResumes->Count());
-}
-
-TEST_F(ImageStreamingLexer, ZeroLengthStateWithUnbuffered)
-{
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- // Create a special StreamingLexer for this test because we want the first
- // state to be both zero length and unbuffered.
- StreamingLexer<TestState> lexer(Transition::ToUnbuffered(TestState::ONE,
- TestState::UNBUFFERED,
- 0),
- Transition::TerminateFailure());
-
- LexerResult result =
- lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStatesUnbuffered);
-
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, ZeroLengthStateAfterUnbuffered)
-{
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- // Create a special StreamingLexer for this test because we want the first
- // state to be zero length.
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 0),
- Transition::TerminateFailure());
-
- LexerResult result =
- lexer.Lex(mIterator, mExpectNoResume, DoLexWithZeroLengthStatesAfterUnbuffered);
-
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, ZeroLengthStateWithUnbufferedYield)
-{
- size_t unbufferedCallCount = 0;
- auto lexerFunc = [&](TestState aState, const char* aData, size_t aLength)
- -> LexerTransition<TestState> {
- switch (aState) {
- case TestState::ONE:
- EXPECT_EQ(0u, aLength);
- return Transition::TerminateSuccess();
-
- case TestState::UNBUFFERED:
- switch (unbufferedCallCount) {
- case 0:
- CheckLexedData(aData, aLength, 0, 3);
- unbufferedCallCount++;
-
- // Continue after yield, telling StreamingLexer we consumed 0 bytes.
- return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 0);
-
- case 1:
- CheckLexedData(aData, aLength, 0, 3);
- unbufferedCallCount++;
-
- // Continue after yield, telling StreamingLexer we consumed 2 bytes.
- return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 2);
-
- case 2:
- EXPECT_EQ(1u, aLength);
- CheckLexedData(aData, aLength, 2, 1);
- unbufferedCallCount++;
-
- // Continue after yield, telling StreamingLexer we consumed 1 bytes.
- return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 1);
-
- case 3:
- CheckLexedData(aData, aLength, 3, 6);
- unbufferedCallCount++;
-
- // Continue after yield, telling StreamingLexer we consumed 6 bytes.
- // We should transition to TestState::ONE when we return from the
- // yield.
- return Transition::ContinueUnbufferedAfterYield(TestState::UNBUFFERED, 6);
- }
-
- ADD_FAILURE() << "Too many invocations of TestState::UNBUFFERED";
- return Transition::TerminateFailure();
-
- default:
- MOZ_CRASH("Unexpected or unhandled TestState");
- }
- };
-
- // Create a special StreamingLexer for this test because we want the first
- // state to be unbuffered.
- StreamingLexer<TestState> lexer(Transition::ToUnbuffered(TestState::ONE,
- TestState::UNBUFFERED,
- sizeof(mData)),
- Transition::TerminateFailure());
-
- mSourceBuffer->Append(mData, 3);
- LexerResult result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
- ASSERT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
- EXPECT_EQ(1u, unbufferedCallCount);
-
- result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
- ASSERT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
- EXPECT_EQ(2u, unbufferedCallCount);
-
- result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
- ASSERT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
- EXPECT_EQ(3u, unbufferedCallCount);
-
- result = lexer.Lex(mIterator, mCountResumes, lexerFunc);
- ASSERT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- EXPECT_EQ(3u, unbufferedCallCount);
-
- mSourceBuffer->Append(mData + 3, 6);
- mSourceBuffer->Complete(NS_OK);
- EXPECT_EQ(1u, mCountResumes->Count());
- result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
- ASSERT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
- EXPECT_EQ(4u, unbufferedCallCount);
-
- result = lexer.Lex(mIterator, mExpectNoResume, lexerFunc);
- ASSERT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, TerminateSuccess)
-{
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- // Test that Terminate is "sticky".
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
- LexerResult result =
- mLexer.Lex(iterator, mExpectNoResume,
- [&](TestState aState, const char* aData, size_t aLength) {
- EXPECT_TRUE(aState == TestState::ONE);
- return Transition::TerminateSuccess();
- });
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-
- SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
- result =
- mLexer.Lex(iterator2, mExpectNoResume,
- [&](TestState aState, const char* aData, size_t aLength) {
- EXPECT_TRUE(false); // Shouldn't get here.
- return Transition::TerminateFailure();
- });
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, TerminateFailure)
-{
- mSourceBuffer->Append(mData, sizeof(mData));
- mSourceBuffer->Complete(NS_OK);
-
- // Test that Terminate is "sticky".
- SourceBufferIterator iterator = mSourceBuffer->Iterator();
- LexerResult result =
- mLexer.Lex(iterator, mExpectNoResume,
- [&](TestState aState, const char* aData, size_t aLength) {
- EXPECT_TRUE(aState == TestState::ONE);
- return Transition::TerminateFailure();
- });
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
-
- SourceBufferIterator iterator2 = mSourceBuffer->Iterator();
- result =
- mLexer.Lex(iterator2, mExpectNoResume,
- [&](TestState aState, const char* aData, size_t aLength) {
- EXPECT_TRUE(false); // Shouldn't get here.
- return Transition::TerminateFailure();
- });
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, TerminateUnbuffered)
-{
- // Test that Terminate works during an unbuffered read.
- for (unsigned i = 0; i < 9; ++i) {
- mSourceBuffer->Append(mData + i, 1);
- LexerResult result =
- mLexer.Lex(mIterator, mCountResumes, DoLexWithUnbufferedTerminate);
-
- if (i > 2) {
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- } else {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- // We expect 3 resumes because TestState::ONE consumes 3 bytes and then
- // transitions to TestState::UNBUFFERED, which calls TerminateSuccess() as
- // soon as it receives a single byte. That's four bytes total, which are
- // delivered one at a time, requiring 3 resumes.
- EXPECT_EQ(3u, mCountResumes->Count());
-
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, TerminateAfterYield)
-{
- // Test that Terminate works after yielding.
- for (unsigned i = 0; i < 9; ++i) {
- mSourceBuffer->Append(mData + i, 1);
- LexerResult result =
- mLexer.Lex(mIterator, mCountResumes, DoLexWithTerminateAfterYield);
-
- if (i > 2) {
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- } else if (i == 2) {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::OUTPUT_AVAILABLE, result.as<Yield>());
- } else {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- // We expect 2 resumes because TestState::ONE consumes 3 bytes and then
- // yields. When the lexer resumes at TestState::TWO, which receives the same 3
- // bytes, TerminateSuccess() gets called immediately. That's three bytes
- // total, which are delivered one at a time, requiring 2 resumes.
- EXPECT_EQ(2u, mCountResumes->Count());
-
- mSourceBuffer->Complete(NS_OK);
-}
-
-TEST_F(ImageStreamingLexer, SourceBufferImmediateComplete)
-{
- // Test calling SourceBuffer::Complete() without appending any data. This
- // causes the SourceBuffer to automatically have a failing completion status,
- // no matter what you pass, so we expect TerminalState::FAILURE below.
- mSourceBuffer->Complete(NS_OK);
-
- LexerResult result = mLexer.Lex(mIterator, mExpectNoResume, DoLex);
-
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::FAILURE, result.as<TerminalState>());
-}
-
-TEST_F(ImageStreamingLexer, SourceBufferTruncatedTerminalStateSuccess)
-{
- // Test that using a terminal state (in this case TerminalState::SUCCESS) as a
- // truncated state works.
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
- Transition::TerminateSuccess());
-
- CheckTruncatedState(lexer, TerminalState::SUCCESS);
-}
-
-TEST_F(ImageStreamingLexer, SourceBufferTruncatedTerminalStateFailure)
-{
- // Test that using a terminal state (in this case TerminalState::FAILURE) as a
- // truncated state works.
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
- Transition::TerminateFailure());
-
- CheckTruncatedState(lexer, TerminalState::FAILURE);
-}
-
-TEST_F(ImageStreamingLexer, SourceBufferTruncatedStateReturningSuccess)
-{
- // Test that a truncated state that returns TerminalState::SUCCESS works. When
- // |lexer| discovers that the data is truncated, it invokes the
- // TRUNCATED_SUCCESS state, which returns TerminalState::SUCCESS.
- // CheckTruncatedState() verifies that this happens.
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
- Transition::To(TestState::TRUNCATED_SUCCESS, 0));
-
- CheckTruncatedState(lexer, TerminalState::SUCCESS);
-}
-
-TEST_F(ImageStreamingLexer, SourceBufferTruncatedStateReturningFailure)
-{
- // Test that a truncated state that returns TerminalState::FAILURE works. When
- // |lexer| discovers that the data is truncated, it invokes the
- // TRUNCATED_FAILURE state, which returns TerminalState::FAILURE.
- // CheckTruncatedState() verifies that this happens.
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
- Transition::To(TestState::TRUNCATED_FAILURE, 0));
-
- CheckTruncatedState(lexer, TerminalState::FAILURE);
-}
-
-TEST_F(ImageStreamingLexer, SourceBufferTruncatedFailingCompleteStatus)
-{
- // Test that calling SourceBuffer::Complete() with a failing status results in
- // an immediate TerminalState::FAILURE result. (Note that |lexer|'s truncated
- // state is TerminalState::SUCCESS, so if we ignore the failing status, the
- // test will fail.)
- StreamingLexer<TestState> lexer(Transition::To(TestState::ONE, 3),
- Transition::TerminateSuccess());
-
- CheckTruncatedState(lexer, TerminalState::FAILURE, NS_ERROR_FAILURE);
-}
-
-TEST_F(ImageStreamingLexer, NoSourceBufferResumable)
-{
- // Test delivering in one byte chunks with no IResumable.
- for (unsigned i = 0; i < 9; ++i) {
- mSourceBuffer->Append(mData + i, 1);
- LexerResult result = mLexer.Lex(mIterator, nullptr, DoLex);
-
- if (i == 8) {
- EXPECT_TRUE(result.is<TerminalState>());
- EXPECT_EQ(TerminalState::SUCCESS, result.as<TerminalState>());
- } else {
- EXPECT_TRUE(result.is<Yield>());
- EXPECT_EQ(Yield::NEED_MORE_DATA, result.as<Yield>());
- }
- }
-
- mSourceBuffer->Complete(NS_OK);
-}
diff --git a/image/test/gtest/TestSurfacePipeIntegration.cpp b/image/test/gtest/TestSurfacePipeIntegration.cpp
deleted file mode 100644
index 27138a3ee..000000000
--- a/image/test/gtest/TestSurfacePipeIntegration.cpp
+++ /dev/null
@@ -1,508 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "mozilla/gfx/2D.h"
-#include "Common.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "SourceBuffer.h"
-#include "SurfacePipe.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-namespace mozilla {
-namespace image {
-
-class TestSurfacePipeFactory
-{
-public:
- static SurfacePipe SimpleSurfacePipe()
- {
- SurfacePipe pipe;
- return Move(pipe);
- }
-
- template <typename T>
- static SurfacePipe SurfacePipeFromPipeline(T&& aPipeline)
- {
- return SurfacePipe { Move(aPipeline) };
- }
-
-private:
- TestSurfacePipeFactory() { }
-};
-
-} // namespace image
-} // namespace mozilla
-
-void
-CheckSurfacePipeMethodResults(SurfacePipe* aPipe,
- Decoder* aDecoder,
- const IntRect& aRect = IntRect(0, 0, 100, 100))
-{
- // Check that the pipeline ended up in the state we expect. Note that we're
- // explicitly testing the SurfacePipe versions of these methods, so we don't
- // want to use AssertCorrectPipelineFinalState() here.
- EXPECT_TRUE(aPipe->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aPipe->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 0, 100, 100), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 0, 100, 100), invalidRect->mOutputSpaceRect);
-
- // Check the generated image.
- CheckGeneratedImage(aDecoder, aRect);
-
- // Reset and clear the image before the next test.
- aPipe->ResetToFirstRow();
- EXPECT_FALSE(aPipe->IsSurfaceFinished());
- invalidRect = aPipe->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- uint32_t count = 0;
- auto result = aPipe->WritePixels<uint32_t>([&]() {
- ++count;
- return AsVariant(BGRAColor::Transparent().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
-
- EXPECT_TRUE(aPipe->IsSurfaceFinished());
- invalidRect = aPipe->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 0, 100, 100), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 0, 100, 100), invalidRect->mOutputSpaceRect);
-
- aPipe->ResetToFirstRow();
- EXPECT_FALSE(aPipe->IsSurfaceFinished());
- invalidRect = aPipe->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-}
-
-void
-CheckPalettedSurfacePipeMethodResults(SurfacePipe* aPipe,
- Decoder* aDecoder,
- const IntRect& aRect
- = IntRect(0, 0, 100, 100))
-{
- // Check that the pipeline ended up in the state we expect. Note that we're
- // explicitly testing the SurfacePipe versions of these methods, so we don't
- // want to use AssertCorrectPipelineFinalState() here.
- EXPECT_TRUE(aPipe->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aPipe->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 0, 100, 100), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 0, 100, 100), invalidRect->mOutputSpaceRect);
-
- // Check the generated image.
- CheckGeneratedPalettedImage(aDecoder, aRect);
-
- // Reset and clear the image before the next test.
- aPipe->ResetToFirstRow();
- EXPECT_FALSE(aPipe->IsSurfaceFinished());
- invalidRect = aPipe->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- uint32_t count = 0;
- auto result = aPipe->WritePixels<uint8_t>([&]() {
- ++count;
- return AsVariant(uint8_t(0));
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
-
- EXPECT_TRUE(aPipe->IsSurfaceFinished());
- invalidRect = aPipe->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 0, 100, 100), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 0, 100, 100), invalidRect->mOutputSpaceRect);
-
- aPipe->ResetToFirstRow();
- EXPECT_FALSE(aPipe->IsSurfaceFinished());
- invalidRect = aPipe->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-}
-
-class ImageSurfacePipeIntegration : public ::testing::Test
-{
-protected:
- AutoInitializeImageLib mInit;
-};
-
-TEST_F(ImageSurfacePipeIntegration, SurfacePipe)
-{
- // Test that SurfacePipe objects can be initialized and move constructed.
- SurfacePipe pipe = TestSurfacePipeFactory::SimpleSurfacePipe();
-
- // Test that SurfacePipe objects can be move assigned.
- pipe = TestSurfacePipeFactory::SimpleSurfacePipe();
-
- // Test that SurfacePipe objects can be initialized with a pipeline.
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- auto sink = MakeUnique<SurfaceSink>();
- nsresult rv =
- sink->Configure(SurfaceConfig { decoder, IntSize(100, 100),
- SurfaceFormat::B8G8R8A8, false });
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- pipe = TestSurfacePipeFactory::SurfacePipeFromPipeline(sink);
-
- // Test that WritePixels() gets passed through to the underlying pipeline.
- {
- uint32_t count = 0;
- auto result = pipe.WritePixels<uint32_t>([&]() {
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
- CheckSurfacePipeMethodResults(&pipe, decoder);
- }
-
- // Create a buffer the same size as one row of the surface, containing all
- // green pixels. We'll use this for the WriteBuffer() tests.
- uint32_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = BGRAColor::Green().AsPixel();
- }
-
- // Test that WriteBuffer() gets passed through to the underlying pipeline.
- {
- uint32_t count = 0;
- WriteState result = WriteState::NEED_MORE_DATA;
- while (result == WriteState::NEED_MORE_DATA) {
- result = pipe.WriteBuffer(buffer);
- ++count;
- }
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, count);
- CheckSurfacePipeMethodResults(&pipe, decoder);
- }
-
- // Test that the 3 argument version of WriteBuffer() gets passed through to
- // the underlying pipeline.
- {
- uint32_t count = 0;
- WriteState result = WriteState::NEED_MORE_DATA;
- while (result == WriteState::NEED_MORE_DATA) {
- result = pipe.WriteBuffer(buffer, 0, 100);
- ++count;
- }
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, count);
- CheckSurfacePipeMethodResults(&pipe, decoder);
- }
-
- // Test that WriteEmptyRow() gets passed through to the underlying pipeline.
- {
- uint32_t count = 0;
- WriteState result = WriteState::NEED_MORE_DATA;
- while (result == WriteState::NEED_MORE_DATA) {
- result = pipe.WriteEmptyRow();
- ++count;
- }
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, count);
- CheckSurfacePipeMethodResults(&pipe, decoder, IntRect(0, 0, 0, 0));
- }
-
- // Mark the frame as finished so we don't get an assertion.
- RawAccessFrameRef currentFrame = decoder->GetCurrentFrameRef();
- currentFrame->Finish();
-}
-
-TEST_F(ImageSurfacePipeIntegration, PalettedSurfacePipe)
-{
- // Create a SurfacePipe containing a PalettedSurfaceSink.
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- auto sink = MakeUnique<PalettedSurfaceSink>();
- nsresult rv =
- sink->Configure(PalettedSurfaceConfig { decoder, IntSize(100, 100),
- IntRect(0, 0, 100, 100),
- SurfaceFormat::B8G8R8A8,
- 8, false });
- ASSERT_TRUE(NS_SUCCEEDED(rv));
-
- SurfacePipe pipe = TestSurfacePipeFactory::SurfacePipeFromPipeline(sink);
-
- // Test that WritePixels() gets passed through to the underlying pipeline.
- {
- uint32_t count = 0;
- auto result = pipe.WritePixels<uint8_t>([&]() {
- ++count;
- return AsVariant(uint8_t(255));
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
- CheckPalettedSurfacePipeMethodResults(&pipe, decoder);
- }
-
- // Create a buffer the same size as one row of the surface, containing all
- // 255 pixels. We'll use this for the WriteBuffer() tests.
- uint8_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = 255;
- }
-
- // Test that WriteBuffer() gets passed through to the underlying pipeline.
- {
- uint32_t count = 0;
- WriteState result = WriteState::NEED_MORE_DATA;
- while (result == WriteState::NEED_MORE_DATA) {
- result = pipe.WriteBuffer(buffer);
- ++count;
- }
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, count);
- CheckPalettedSurfacePipeMethodResults(&pipe, decoder);
- }
-
- // Test that the 3 argument version of WriteBuffer() gets passed through to
- // the underlying pipeline.
- {
- uint32_t count = 0;
- WriteState result = WriteState::NEED_MORE_DATA;
- while (result == WriteState::NEED_MORE_DATA) {
- result = pipe.WriteBuffer(buffer, 0, 100);
- ++count;
- }
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, count);
- CheckPalettedSurfacePipeMethodResults(&pipe, decoder);
- }
-
- // Test that WriteEmptyRow() gets passed through to the underlying pipeline.
- {
- uint32_t count = 0;
- WriteState result = WriteState::NEED_MORE_DATA;
- while (result == WriteState::NEED_MORE_DATA) {
- result = pipe.WriteEmptyRow();
- ++count;
- }
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, count);
- CheckPalettedSurfacePipeMethodResults(&pipe, decoder, IntRect(0, 0, 0, 0));
- }
-
- // Mark the frame as finished so we don't get an assertion.
- RawAccessFrameRef currentFrame = decoder->GetCurrentFrameRef();
- currentFrame->Finish();
-}
-
-TEST_F(ImageSurfacePipeIntegration, DeinterlaceDownscaleWritePixels)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- auto test = [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 25, 25)));
- };
-
- WithFilterPipeline(decoder, test,
- DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true },
- DownscalingConfig { IntSize(100, 100),
- SurfaceFormat::B8G8R8A8 },
- SurfaceConfig { decoder, IntSize(25, 25),
- SurfaceFormat::B8G8R8A8, false });
-}
-
-TEST_F(ImageSurfacePipeIntegration, RemoveFrameRectBottomRightDownscaleWritePixels)
-{
- // This test case uses a frame rect that extends beyond the borders of the
- // image to the bottom and to the right. It looks roughly like this (with the
- // box made of '#'s representing the frame rect):
- //
- // +------------+
- // + +
- // + +------------+
- // + +############+
- // +------+############+
- // +############+
- // +------------+
-
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- // Note that aInputWriteRect is 100x50 because RemoveFrameRectFilter ignores
- // trailing rows that don't show up in the output. (Leading rows unfortunately
- // can't be ignored.) So the action of the pipeline is as follows:
- //
- // (1) RemoveFrameRectFilter reads a 100x50 region of the input.
- // (aInputWriteRect captures this fact.) The remaining 50 rows are ignored
- // because they extend off the bottom of the image due to the frame rect's
- // (50, 50) offset. The 50 columns on the right also don't end up in the
- // output, so ultimately only a 50x50 region in the output contains data
- // from the input. The filter's output is not 50x50, though, but 100x100,
- // because what RemoveFrameRectFilter does is introduce blank rows or
- // columns as necessary to transform an image that needs a frame rect into
- // an image that doesn't.
- //
- // (2) DownscalingFilter reads the output of RemoveFrameRectFilter (100x100)
- // and downscales it to 20x20.
- //
- // (3) The surface owned by SurfaceSink logically has only a 10x10 region
- // region in it that's non-blank; this is the downscaled version of the
- // 50x50 region discussed in (1). (aOutputWriteRect captures this fact.)
- // Some fuzz, as usual, is necessary when dealing with Lanczos downscaling.
-
- auto test = [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 20, 20)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(50, 50, 100, 50)),
- /* aOutputWriteRect = */ Some(IntRect(10, 10, 10, 10)),
- /* aFuzz = */ 0x33);
- };
-
- WithFilterPipeline(decoder, test,
- RemoveFrameRectConfig { IntRect(50, 50, 100, 100) },
- DownscalingConfig { IntSize(100, 100),
- SurfaceFormat::B8G8R8A8 },
- SurfaceConfig { decoder, IntSize(20, 20),
- SurfaceFormat::B8G8R8A8, false });
-}
-
-TEST_F(ImageSurfacePipeIntegration, RemoveFrameRectTopLeftDownscaleWritePixels)
-{
- // This test case uses a frame rect that extends beyond the borders of the
- // image to the top and to the left. It looks roughly like this (with the
- // box made of '#'s representing the frame rect):
- //
- // +------------+
- // +############+
- // +############+------+
- // +############+ +
- // +------------+ +
- // + +
- // +------------+
-
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- auto test = [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 20, 20)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aOutputWriteRect = */ Some(IntRect(0, 0, 10, 10)),
- /* aFuzz = */ 0x21);
- };
-
- WithFilterPipeline(decoder, test,
- RemoveFrameRectConfig { IntRect(-50, -50, 100, 100) },
- DownscalingConfig { IntSize(100, 100),
- SurfaceFormat::B8G8R8A8 },
- SurfaceConfig { decoder, IntSize(20, 20),
- SurfaceFormat::B8G8R8A8, false });
-}
-
-TEST_F(ImageSurfacePipeIntegration, DeinterlaceRemoveFrameRectWritePixels)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- // Note that aInputRect is the full 100x100 size even though
- // RemoveFrameRectFilter is part of this pipeline, because deinterlacing
- // requires reading every row.
-
- auto test = [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(50, 50, 100, 100)),
- /* aOutputWriteRect = */ Some(IntRect(50, 50, 50, 50)));
- };
-
- WithFilterPipeline(decoder, test,
- DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true },
- RemoveFrameRectConfig { IntRect(50, 50, 100, 100) },
- SurfaceConfig { decoder, IntSize(100, 100),
- SurfaceFormat::B8G8R8A8, false });
-}
-
-TEST_F(ImageSurfacePipeIntegration, DeinterlaceRemoveFrameRectDownscaleWritePixels)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- auto test = [](Decoder* aDecoder, SurfaceFilter* aFilter) {
- CheckWritePixels(aDecoder, aFilter,
- /* aOutputRect = */ Some(IntRect(0, 0, 20, 20)),
- /* aInputRect = */ Some(IntRect(0, 0, 100, 100)),
- /* aInputWriteRect = */ Some(IntRect(50, 50, 100, 100)),
- /* aOutputWriteRect = */ Some(IntRect(10, 10, 10, 10)),
- /* aFuzz = */ 33);
- };
-
- WithFilterPipeline(decoder, test,
- DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true },
- RemoveFrameRectConfig { IntRect(50, 50, 100, 100) },
- DownscalingConfig { IntSize(100, 100),
- SurfaceFormat::B8G8R8A8 },
- SurfaceConfig { decoder, IntSize(20, 20),
- SurfaceFormat::B8G8R8A8, false });
-}
-
-TEST_F(ImageSurfacePipeIntegration, ConfiguringPalettedRemoveFrameRectDownscaleFails)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- // This is an invalid pipeline for paletted images, so configuration should
- // fail.
- AssertConfiguringPipelineFails(decoder,
- RemoveFrameRectConfig { IntRect(0, 0, 50, 50) },
- DownscalingConfig { IntSize(100, 100),
- SurfaceFormat::B8G8R8A8 },
- PalettedSurfaceConfig { decoder, IntSize(100, 100),
- IntRect(0, 0, 50, 50),
- SurfaceFormat::B8G8R8A8, 8,
- false });
-}
-
-TEST_F(ImageSurfacePipeIntegration, ConfiguringPalettedDeinterlaceDownscaleFails)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- // This is an invalid pipeline for paletted images, so configuration should
- // fail.
- AssertConfiguringPipelineFails(decoder,
- DeinterlacingConfig<uint8_t> { /* mProgressiveDisplay = */ true},
- DownscalingConfig { IntSize(100, 100),
- SurfaceFormat::B8G8R8A8 },
- PalettedSurfaceConfig { decoder, IntSize(100, 100),
- IntRect(0, 0, 20, 20),
- SurfaceFormat::B8G8R8A8, 8,
- false });
-}
-
-TEST_F(ImageSurfacePipeIntegration, ConfiguringHugeDeinterlacingBufferFails)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- // When DownscalingFilter is used, we may succeed in allocating an output
- // surface for huge images, because we only need to store the scaled-down
- // version of the image. However, regardless of downscaling,
- // DeinterlacingFilter needs to allocate a buffer as large as the size of the
- // input. This can cause OOMs on operating systems that allow overcommit. This
- // test makes sure that we reject such allocations.
- AssertConfiguringPipelineFails(decoder,
- DeinterlacingConfig<uint32_t> { /* mProgressiveDisplay = */ true},
- DownscalingConfig { IntSize(60000, 60000),
- SurfaceFormat::B8G8R8A8 },
- SurfaceConfig { decoder, IntSize(600, 600),
- SurfaceFormat::B8G8R8A8, false });
-}
diff --git a/image/test/gtest/TestSurfaceSink.cpp b/image/test/gtest/TestSurfaceSink.cpp
deleted file mode 100644
index 3a1c74d12..000000000
--- a/image/test/gtest/TestSurfaceSink.cpp
+++ /dev/null
@@ -1,1491 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "gtest/gtest.h"
-
-#include "mozilla/gfx/2D.h"
-#include "Common.h"
-#include "Decoder.h"
-#include "DecoderFactory.h"
-#include "SourceBuffer.h"
-#include "SurfacePipe.h"
-
-using namespace mozilla;
-using namespace mozilla::gfx;
-using namespace mozilla::image;
-
-enum class Orient
-{
- NORMAL,
- FLIP_VERTICALLY
-};
-
-template <Orient Orientation, typename Func> void
-WithSurfaceSink(Func aFunc)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- const bool flipVertically = Orientation == Orient::FLIP_VERTICALLY;
-
- WithFilterPipeline(decoder, Forward<Func>(aFunc),
- SurfaceConfig { decoder, IntSize(100, 100),
- SurfaceFormat::B8G8R8A8, flipVertically });
-}
-
-template <typename Func> void
-WithPalettedSurfaceSink(const IntRect& aFrameRect, Func aFunc)
-{
- RefPtr<Decoder> decoder = CreateTrivialDecoder();
- ASSERT_TRUE(decoder != nullptr);
-
- WithFilterPipeline(decoder, Forward<Func>(aFunc),
- PalettedSurfaceConfig { decoder, IntSize(100, 100),
- aFrameRect, SurfaceFormat::B8G8R8A8,
- 8, false });
-}
-
-void
-ResetForNextPass(SurfaceFilter* aSink)
-{
- aSink->ResetToFirstRow();
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-}
-
-template <typename WriteFunc, typename CheckFunc> void
-DoCheckIterativeWrite(SurfaceFilter* aSink,
- WriteFunc aWriteFunc,
- CheckFunc aCheckFunc)
-{
- // Write the buffer to successive rows until every row of the surface
- // has been written.
- uint32_t row = 0;
- WriteState result = WriteState::NEED_MORE_DATA;
- while (result == WriteState::NEED_MORE_DATA) {
- result = aWriteFunc(row);
- ++row;
- }
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, row);
-
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Check that the generated image is correct.
- aCheckFunc();
-}
-
-template <typename WriteFunc> void
-CheckIterativeWrite(Decoder* aDecoder,
- SurfaceSink* aSink,
- const IntRect& aOutputRect,
- WriteFunc aWriteFunc)
-{
- // Ignore the row passed to WriteFunc, since no callers use it.
- auto writeFunc = [&](uint32_t) {
- return aWriteFunc();
- };
-
- DoCheckIterativeWrite(aSink, writeFunc, [&]{
- CheckGeneratedImage(aDecoder, aOutputRect);
- });
-}
-
-template <typename WriteFunc> void
-CheckPalettedIterativeWrite(Decoder* aDecoder,
- PalettedSurfaceSink* aSink,
- const IntRect& aOutputRect,
- WriteFunc aWriteFunc)
-{
- // Ignore the row passed to WriteFunc, since no callers use it.
- auto writeFunc = [&](uint32_t) {
- return aWriteFunc();
- };
-
- DoCheckIterativeWrite(aSink, writeFunc, [&]{
- CheckGeneratedPalettedImage(aDecoder, aOutputRect);
- });
-}
-
-TEST(ImageSurfaceSink, NullSurfaceSink)
-{
- // Create the NullSurfaceSink.
- NullSurfaceSink sink;
- nsresult rv = sink.Configure(NullSurfaceConfig { });
- ASSERT_TRUE(NS_SUCCEEDED(rv));
- EXPECT_TRUE(!sink.IsValidPalettedPipe());
-
- // Ensure that we can't write anything.
- bool gotCalled = false;
- auto result = sink.WritePixels<uint32_t>([&]() {
- gotCalled = true;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_FALSE(gotCalled);
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_TRUE(sink.IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = sink.TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- uint32_t source = BGRAColor::Red().AsPixel();
- result = sink.WriteBuffer(&source);
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_TRUE(sink.IsSurfaceFinished());
- invalidRect = sink.TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- result = sink.WriteBuffer(&source, 0, 1);
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_TRUE(sink.IsSurfaceFinished());
- invalidRect = sink.TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- result = sink.WriteEmptyRow();
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_TRUE(sink.IsSurfaceFinished());
- invalidRect = sink.TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- result = sink.WriteUnsafeComputedRow<uint32_t>([&](uint32_t* aRow,
- uint32_t aLength) {
- gotCalled = true;
- for (uint32_t col = 0; col < aLength; ++col, ++aRow) {
- *aRow = BGRAColor::Red().AsPixel();
- }
- });
- EXPECT_FALSE(gotCalled);
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_TRUE(sink.IsSurfaceFinished());
- invalidRect = sink.TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Attempt to advance to the next row and make sure nothing changes.
- sink.AdvanceRow();
- EXPECT_TRUE(sink.IsSurfaceFinished());
- invalidRect = sink.TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Attempt to advance to the next pass and make sure nothing changes.
- sink.ResetToFirstRow();
- EXPECT_TRUE(sink.IsSurfaceFinished());
- invalidRect = sink.TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkInitialization)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Check initial state.
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Check that the surface is zero-initialized. We verify this by calling
- // CheckGeneratedImage() and telling it that we didn't write to the surface
- // anyway (i.e., we wrote to the empty rect); it will then expect the entire
- // surface to be transparent, which is what it should be if it was
- // zero-initialied.
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 0, 0));
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWritePixels)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- CheckWritePixels(aDecoder, aSink);
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWritePixelsFinish)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Write nothing into the surface; just finish immediately.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() {
- count++;
- return AsVariant(WriteState::FINISHED);
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(1u, count);
-
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Attempt to write more and make sure that nothing gets written.
- count = 0;
- result = aSink->WritePixels<uint32_t>([&]() {
- count++;
- return AsVariant(BGRAColor::Red().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(0u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Check that the generated image is correct.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Transparent()));
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWritePixelsEarlyExit)
-{
- auto checkEarlyExit =
- [](Decoder* aDecoder, SurfaceSink* aSink, WriteState aState) {
- // Write half a row of green pixels and then exit early with |aState|. If
- // the lambda keeps getting called, we'll write red pixels, which will cause
- // the test to fail.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 50) {
- return AsVariant(aState);
- }
- return count++ < 50 ? AsVariant(BGRAColor::Green().AsPixel())
- : AsVariant(BGRAColor::Red().AsPixel());
- });
-
- EXPECT_EQ(aState, result);
- EXPECT_EQ(50u, count);
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 50, 1));
-
- if (aState != WriteState::FINISHED) {
- // We should still be able to write more at this point.
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Verify that we can resume writing. We'll finish up the same row.
- count = 0;
- result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 50) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
-
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(50u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, 1));
-
- return;
- }
-
- // We should've finished the surface at this point.
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Attempt to write more and make sure that nothing gets written.
- count = 0;
- result = aSink->WritePixels<uint32_t>([&]{
- count++;
- return AsVariant(BGRAColor::Red().AsPixel());
- });
-
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(0u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Check that the generated image is still correct.
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 50, 1));
- };
-
- WithSurfaceSink<Orient::NORMAL>([&](Decoder* aDecoder, SurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::NEED_MORE_DATA);
- });
-
- WithSurfaceSink<Orient::NORMAL>([&](Decoder* aDecoder, SurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::FAILURE);
- });
-
- WithSurfaceSink<Orient::NORMAL>([&](Decoder* aDecoder, SurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::FINISHED);
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWritePixelsToRow)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Write the first 99 rows of our 100x100 surface and verify that even
- // though our lambda will yield pixels forever, only one row is written per
- // call to WritePixelsToRow().
- for (int row = 0; row < 99; ++row) {
- uint32_t count = 0;
- WriteState result = aSink->WritePixelsToRow<uint32_t>([&]{
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
-
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(100u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, row, 100, 1), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, row, 100, 1), invalidRect->mOutputSpaceRect);
-
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, row + 1));
- }
-
- // Write the final line, which should finish the surface.
- uint32_t count = 0;
- WriteState result = aSink->WritePixelsToRow<uint32_t>([&]{
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
-
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, count);
-
- // Note that the final invalid rect we expect here is only the last row;
- // that's because we called TakeInvalidRect() repeatedly in the loop above.
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 99, 100, 1),
- IntRect(0, 99, 100, 1));
-
- // Check that the generated image is correct.
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, 100));
-
- // Attempt to write more and make sure that nothing gets written.
- count = 0;
- result = aSink->WritePixelsToRow<uint32_t>([&]{
- count++;
- return AsVariant(BGRAColor::Red().AsPixel());
- });
-
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(0u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Check that the generated image is still correct.
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, 100));
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWritePixelsToRowEarlyExit)
-{
- auto checkEarlyExit =
- [](Decoder* aDecoder, SurfaceSink* aSink, WriteState aState) {
- // Write half a row of green pixels and then exit early with |aState|. If
- // the lambda keeps getting called, we'll write red pixels, which will cause
- // the test to fail.
- uint32_t count = 0;
- auto result = aSink->WritePixelsToRow<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 50) {
- return AsVariant(aState);
- }
- return count++ < 50 ? AsVariant(BGRAColor::Green().AsPixel())
- : AsVariant(BGRAColor::Red().AsPixel());
- });
-
- EXPECT_EQ(aState, result);
- EXPECT_EQ(50u, count);
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 50, 1));
-
- if (aState != WriteState::FINISHED) {
- // We should still be able to write more at this point.
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Verify that we can resume the same row and still stop at the end.
- count = 0;
- WriteState result = aSink->WritePixelsToRow<uint32_t>([&]{
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
-
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(50u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 100, 1));
-
- return;
- }
-
- // We should've finished the surface at this point.
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Attempt to write more and make sure that nothing gets written.
- count = 0;
- result = aSink->WritePixelsToRow<uint32_t>([&]{
- count++;
- return AsVariant(BGRAColor::Red().AsPixel());
- });
-
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(0u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Check that the generated image is still correct.
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 50, 1));
- };
-
- WithSurfaceSink<Orient::NORMAL>([&](Decoder* aDecoder, SurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::NEED_MORE_DATA);
- });
-
- WithSurfaceSink<Orient::NORMAL>([&](Decoder* aDecoder, SurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::FAILURE);
- });
-
- WithSurfaceSink<Orient::NORMAL>([&](Decoder* aDecoder, SurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::FINISHED);
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWriteBuffer)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Create a green buffer the same size as one row of the surface (which is 100x100),
- // containing 60 pixels of green in the middle and 20 transparent pixels on
- // either side.
- uint32_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = 20 <= i && i < 80 ? BGRAColor::Green().AsPixel()
- : BGRAColor::Transparent().AsPixel();
- }
-
- // Write the buffer to every row of the surface and check that the generated
- // image is correct.
- CheckIterativeWrite(aDecoder, aSink, IntRect(20, 0, 60, 100), [&]{
- return aSink->WriteBuffer(buffer);
- });
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWriteBufferPartialRow)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Create a buffer the same size as one row of the surface, containing all
- // green pixels.
- uint32_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = BGRAColor::Green().AsPixel();
- }
-
- // Write the buffer to the middle 60 pixels of every row of the surface and
- // check that the generated image is correct.
- CheckIterativeWrite(aDecoder, aSink, IntRect(20, 0, 60, 100), [&]{
- return aSink->WriteBuffer(buffer, 20, 60);
- });
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWriteBufferPartialRowStartColOverflow)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Create a buffer the same size as one row of the surface, containing all
- // green pixels.
- uint32_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = BGRAColor::Green().AsPixel();
- }
-
- {
- // Write the buffer to successive rows until every row of the surface
- // has been written. We place the start column beyond the end of the row,
- // which will prevent us from writing anything, so we check that the
- // generated image is entirely transparent.
- CheckIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0), [&]{
- return aSink->WriteBuffer(buffer, 100, 100);
- });
- }
-
- ResetForNextPass(aSink);
-
- {
- // Write the buffer to successive rows until every row of the surface
- // has been written. We use column 50 as the start column, but we still
- // write the buffer, which means we overflow the right edge of the surface
- // by 50 pixels. We check that the left half of the generated image is
- // transparent and the right half is green.
- CheckIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100), [&]{
- return aSink->WriteBuffer(buffer, 50, 100);
- });
- }
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWriteBufferPartialRowBufferOverflow)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Create a buffer twice as large as a row of the surface. The first half
- // (which is as large as a row of the image) will contain green pixels,
- // while the second half will contain red pixels.
- uint32_t buffer[200];
- for (int i = 0; i < 200; ++i) {
- buffer[i] = i < 100 ? BGRAColor::Green().AsPixel()
- : BGRAColor::Red().AsPixel();
- }
-
- {
- // Write the buffer to successive rows until every row of the surface has
- // been written. The buffer extends 100 pixels to the right of a row of
- // the surface, but bounds checking will prevent us from overflowing the
- // buffer. We check that the generated image is entirely green since the
- // pixels on the right side of the buffer shouldn't have been written to
- // the surface.
- CheckIterativeWrite(aDecoder, aSink, IntRect(0, 0, 100, 100), [&]{
- return aSink->WriteBuffer(buffer, 0, 200);
- });
- }
-
- ResetForNextPass(aSink);
-
- {
- // Write from the buffer to the middle of each row of the surface. That
- // means that the left side of each row should be transparent, since we
- // didn't write anything there. A buffer overflow would cause us to write
- // buffer contents into the left side of each row. We check that the
- // generated image is transparent on the left side and green on the right.
- CheckIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100), [&]{
- return aSink->WriteBuffer(buffer, 50, 200);
- });
- }
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWriteBufferFromNullSource)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Calling WriteBuffer() with a null pointer should fail without making any
- // changes to the surface.
- uint32_t* nullBuffer = nullptr;
- WriteState result = aSink->WriteBuffer(nullBuffer);
-
- EXPECT_EQ(WriteState::FAILURE, result);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Check that nothing got written to the surface.
- CheckGeneratedImage(aDecoder, IntRect(0, 0, 0, 0));
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWriteEmptyRow)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- {
- // Write an empty row to each row of the surface. We check that the
- // generated image is entirely transparent.
- CheckIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0), [&]{
- return aSink->WriteEmptyRow();
- });
- }
-
- ResetForNextPass(aSink);
-
- {
- // Write a partial row before we begin calling WriteEmptyRow(). We check
- // that the generated image is entirely transparent, which is to be
- // expected since WriteEmptyRow() overwrites the current row even if some
- // data has already been written to it.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 50) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
-
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(50u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- CheckIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0), [&]{
- return aSink->WriteEmptyRow();
- });
- }
-
- ResetForNextPass(aSink);
-
- {
- // Create a buffer the same size as one row of the surface, containing all
- // green pixels.
- uint32_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = BGRAColor::Green().AsPixel();
- }
-
- // Write an empty row to the middle 60 rows of the surface. The first 20
- // and last 20 rows will be green. (We need to use DoCheckIterativeWrite()
- // here because we need a custom function to check the output, since it
- // can't be described by a simple rect.)
- auto writeFunc = [&](uint32_t aRow) {
- if (aRow < 20 || aRow >= 80) {
- return aSink->WriteBuffer(buffer);
- } else {
- return aSink->WriteEmptyRow();
- }
- };
-
- auto checkFunc = [&]{
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
-
- EXPECT_TRUE(RowsAreSolidColor(surface, 0, 20, BGRAColor::Green()));
- EXPECT_TRUE(RowsAreSolidColor(surface, 20, 60, BGRAColor::Transparent()));
- EXPECT_TRUE(RowsAreSolidColor(surface, 80, 20, BGRAColor::Green()));
- };
-
- DoCheckIterativeWrite(aSink, writeFunc, checkFunc);
- }
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkWriteUnsafeComputedRow)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- // Create a green buffer the same size as one row of the surface.
- uint32_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = BGRAColor::Green().AsPixel();
- }
-
- // Write the buffer to successive rows until every row of the surface
- // has been written. We only write to the right half of each row, so we
- // check that the left side of the generated image is transparent and the
- // right side is green.
- CheckIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100), [&]{
- return aSink->WriteUnsafeComputedRow<uint32_t>([&](uint32_t* aRow,
- uint32_t aLength) {
- EXPECT_EQ(100u, aLength );
- memcpy(aRow + 50, buffer, 50 * sizeof(uint32_t));
- });
- });
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkProgressivePasses)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- {
- // Fill the image with a first pass of red.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() {
- ++count;
- return AsVariant(BGRAColor::Red().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
-
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Check that the generated image is correct.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Red()));
- }
-
- {
- ResetForNextPass(aSink);
-
- // Check that the generated image is still the first pass image.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Red()));
- }
-
- {
- // Fill the image with a second pass of green.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() {
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
-
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Check that the generated image is correct.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green()));
- }
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkInvalidRect)
-{
- WithSurfaceSink<Orient::NORMAL>([](Decoder* aDecoder, SurfaceSink* aSink) {
- {
- // Write one row.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 100) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- count++;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(100u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Assert that we have the right invalid rect.
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 0, 100, 1), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 0, 100, 1), invalidRect->mOutputSpaceRect);
- }
-
- {
- // Write eight rows.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 100 * 8) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- count++;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(100u * 8u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Assert that we have the right invalid rect.
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 1, 100, 8), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 1, 100, 8), invalidRect->mOutputSpaceRect);
- }
-
- {
- // Write the left half of one row.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 50) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- count++;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(50u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Assert that we don't have an invalid rect, since the invalid rect only
- // gets updated when a row gets completed.
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
- }
-
- {
- // Write the right half of the same row.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 50) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- count++;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(50u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Assert that we have the right invalid rect, which will include both the
- // left and right halves of this row now that we've completed it.
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 9, 100, 1), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 9, 100, 1), invalidRect->mOutputSpaceRect);
- }
-
- {
- // Write no rows.
- auto result = aSink->WritePixels<uint32_t>([&]() {
- return AsVariant(WriteState::NEED_MORE_DATA);
- });
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Assert that we don't have an invalid rect.
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
- }
-
- {
- // Fill the rest of the image.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() {
- count++;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 90u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Assert that we have the right invalid rect.
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 10, 100, 90), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 10, 100, 90), invalidRect->mOutputSpaceRect);
-
- // Check that the generated image is correct.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green()));
- }
- });
-}
-
-TEST(ImageSurfaceSink, SurfaceSinkFlipVertically)
-{
- WithSurfaceSink<Orient::FLIP_VERTICALLY>([](Decoder* aDecoder,
- SurfaceSink* aSink) {
- {
- // Fill the image with a first pass of red.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() {
- ++count;
- return AsVariant(BGRAColor::Red().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u * 100u, count);
-
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Check that the generated image is correct.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Red()));
- }
-
- {
- ResetForNextPass(aSink);
-
- // Check that the generated image is still the first pass image.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Red()));
- }
-
- {
- // Fill 25 rows of the image with green and make sure everything is OK.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() -> NextPixel<uint32_t> {
- if (count == 25 * 100) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- count++;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(25u * 100u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Assert that we have the right invalid rect, which should include the
- // *bottom* (since we're flipping vertically) 25 rows of the image.
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, 75, 100, 25), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, 75, 100, 25), invalidRect->mOutputSpaceRect);
-
- // Check that the generated image is correct.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(RowsAreSolidColor(surface, 0, 75, BGRAColor::Red()));
- EXPECT_TRUE(RowsAreSolidColor(surface, 75, 25, BGRAColor::Green()));
- }
-
- {
- // Fill the rest of the image with a second pass of green.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint32_t>([&]() {
- ++count;
- return AsVariant(BGRAColor::Green().AsPixel());
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(75u * 100u, count);
-
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 75),
- IntRect(0, 0, 100, 75));
-
- // Check that the generated image is correct.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
- EXPECT_TRUE(IsSolidColor(surface, BGRAColor::Green()));
- }
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkInitialization)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Check initial state.
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Check that the paletted image data is zero-initialized.
- RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
- uint8_t* imageData = nullptr;
- uint32_t imageLength = 0;
- currentFrame->GetImageData(&imageData, &imageLength);
- ASSERT_TRUE(imageData != nullptr);
- ASSERT_EQ(100u * 100u, imageLength);
- for (uint32_t i = 0; i < imageLength; ++i) {
- ASSERT_EQ(uint8_t(0), imageData[i]);
- }
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsFor0_0_100_100)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- CheckPalettedWritePixels(aDecoder, aSink);
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsFor25_25_50_50)
-{
- WithPalettedSurfaceSink(IntRect(25, 25, 50, 50),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- CheckPalettedWritePixels(aDecoder, aSink,
- /* aOutputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputWriteRect = */ Some(IntRect(25, 25, 50, 50)),
- /* aOutputWriteRect = */ Some(IntRect(25, 25, 50, 50)));
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsForMinus25_Minus25_50_50)
-{
- WithPalettedSurfaceSink(IntRect(-25, -25, 50, 50),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- CheckPalettedWritePixels(aDecoder, aSink,
- /* aOutputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputWriteRect = */ Some(IntRect(-25, -25, 50, 50)),
- /* aOutputWriteRect = */ Some(IntRect(-25, -25, 50, 50)));
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsFor75_Minus25_50_50)
-{
- WithPalettedSurfaceSink(IntRect(75, -25, 50, 50),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- CheckPalettedWritePixels(aDecoder, aSink,
- /* aOutputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputWriteRect = */ Some(IntRect(75, -25, 50, 50)),
- /* aOutputWriteRect = */ Some(IntRect(75, -25, 50, 50)));
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsForMinus25_75_50_50)
-{
- WithPalettedSurfaceSink(IntRect(-25, 75, 50, 50),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- CheckPalettedWritePixels(aDecoder, aSink,
- /* aOutputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputWriteRect = */ Some(IntRect(-25, 75, 50, 50)),
- /* aOutputWriteRect = */ Some(IntRect(-25, 75, 50, 50)));
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsFor75_75_50_50)
-{
- WithPalettedSurfaceSink(IntRect(75, 75, 50, 50),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- CheckPalettedWritePixels(aDecoder, aSink,
- /* aOutputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputRect = */ Some(IntRect(0, 0, 50, 50)),
- /* aInputWriteRect = */ Some(IntRect(75, 75, 50, 50)),
- /* aOutputWriteRect = */ Some(IntRect(75, 75, 50, 50)));
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsFinish)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Write nothing into the surface; just finish immediately.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint8_t>([&]{
- count++;
- return AsVariant(WriteState::FINISHED);
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(1u, count);
-
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Attempt to write more and make sure that nothing gets written.
- count = 0;
- result = aSink->WritePixels<uint8_t>([&]() {
- count++;
- return AsVariant(uint8_t(128));
- });
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(0u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Check that the generated image is correct.
- EXPECT_TRUE(IsSolidPalettedColor(aDecoder, 0));
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsEarlyExit)
-{
- auto checkEarlyExit =
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink, WriteState aState) {
- // Write half a row of green pixels and then exit early with |aState|. If
- // the lambda keeps getting called, we'll write red pixels, which will cause
- // the test to fail.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint8_t>([&]() -> NextPixel<uint8_t> {
- if (count == 50) {
- return AsVariant(aState);
- }
- return count++ < 50 ? AsVariant(uint8_t(255)) : AsVariant(uint8_t(128));
- });
-
- EXPECT_EQ(aState, result);
- EXPECT_EQ(50u, count);
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 50, 1));
-
- if (aState != WriteState::FINISHED) {
- // We should still be able to write more at this point.
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Verify that we can resume writing. We'll finish up the same row.
- count = 0;
- result = aSink->WritePixels<uint8_t>([&]() -> NextPixel<uint8_t> {
- if (count == 50) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- ++count;
- return AsVariant(uint8_t(255));
- });
-
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(50u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 100, 1));
-
- return;
- }
-
- // We should've finished the surface at this point.
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Attempt to write more and make sure that nothing gets written.
- count = 0;
- result = aSink->WritePixels<uint8_t>([&]{
- count++;
- return AsVariant(uint8_t(128));
- });
-
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(0u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Check that the generated image is still correct.
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 50, 1));
- };
-
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [&](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::NEED_MORE_DATA);
- });
-
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [&](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::FAILURE);
- });
-
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [&](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::FINISHED);
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsToRow)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Write the first 99 rows of our 100x100 surface and verify that even
- // though our lambda will yield pixels forever, only one row is written per
- // call to WritePixelsToRow().
- for (int row = 0; row < 99; ++row) {
- uint32_t count = 0;
- WriteState result = aSink->WritePixelsToRow<uint8_t>([&]{
- ++count;
- return AsVariant(uint8_t(255));
- });
-
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(100u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isSome());
- EXPECT_EQ(IntRect(0, row, 100, 1), invalidRect->mInputSpaceRect);
- EXPECT_EQ(IntRect(0, row, 100, 1), invalidRect->mOutputSpaceRect);
-
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 100, row + 1));
- }
-
- // Write the final line, which should finish the surface.
- uint32_t count = 0;
- WriteState result = aSink->WritePixelsToRow<uint8_t>([&]{
- ++count;
- return AsVariant(uint8_t(255));
- });
-
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(100u, count);
-
- // Note that the final invalid rect we expect here is only the last row;
- // that's because we called TakeInvalidRect() repeatedly in the loop above.
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 99, 100, 1),
- IntRect(0, 99, 100, 1));
-
- // Check that the generated image is correct.
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 100, 100));
-
- // Attempt to write more and make sure that nothing gets written.
- count = 0;
- result = aSink->WritePixelsToRow<uint8_t>([&]{
- count++;
- return AsVariant(uint8_t(128));
- });
-
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(0u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Check that the generated image is still correct.
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 100, 100));
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWritePixelsToRowEarlyExit)
-{
- auto checkEarlyExit =
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink, WriteState aState) {
- // Write half a row of 255s and then exit early with |aState|. If the lambda
- // keeps getting called, we'll write 128s, which will cause the test to
- // fail.
- uint32_t count = 0;
- auto result = aSink->WritePixelsToRow<uint8_t>([&]() -> NextPixel<uint8_t> {
- if (count == 50) {
- return AsVariant(aState);
- }
- return count++ < 50 ? AsVariant(uint8_t(255))
- : AsVariant(uint8_t(128));
- });
-
- EXPECT_EQ(aState, result);
- EXPECT_EQ(50u, count);
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 50, 1));
-
- if (aState != WriteState::FINISHED) {
- // We should still be able to write more at this point.
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- // Verify that we can resume the same row and still stop at the end.
- count = 0;
- WriteState result = aSink->WritePixelsToRow<uint8_t>([&]{
- ++count;
- return AsVariant(uint8_t(255));
- });
-
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(50u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 100, 1));
-
- return;
- }
-
- // We should've finished the surface at this point.
- AssertCorrectPipelineFinalState(aSink,
- IntRect(0, 0, 100, 100),
- IntRect(0, 0, 100, 100));
-
- // Attempt to write more and make sure that nothing gets written.
- count = 0;
- result = aSink->WritePixelsToRow<uint8_t>([&]{
- count++;
- return AsVariant(uint8_t(128));
- });
-
- EXPECT_EQ(WriteState::FINISHED, result);
- EXPECT_EQ(0u, count);
- EXPECT_TRUE(aSink->IsSurfaceFinished());
-
- // Check that the generated image is still correct.
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 50, 1));
- };
-
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [&](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::NEED_MORE_DATA);
- });
-
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [&](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::FAILURE);
- });
-
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [&](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- checkEarlyExit(aDecoder, aSink, WriteState::FINISHED);
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWriteBuffer)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Create a buffer the same size as one row of the surface (which is 100x100),
- // containing 60 pixels of 255 in the middle and 20 transparent pixels of 0 on
- // either side.
- uint8_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = 20 <= i && i < 80 ? 255 : 0;
- }
-
- // Write the buffer to every row of the surface and check that the generated
- // image is correct.
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(20, 0, 60, 100), [&]{
- return aSink->WriteBuffer(buffer);
- });
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWriteBufferPartialRow)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Create a buffer the same size as one row of the surface, containing all
- // 255 pixels.
- uint8_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = 255;
- }
-
- // Write the buffer to the middle 60 pixels of every row of the surface and
- // check that the generated image is correct.
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(20, 0, 60, 100), [&]{
- return aSink->WriteBuffer(buffer, 20, 60);
- });
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWriteBufferPartialRowStartColOverflow)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Create a buffer the same size as one row of the surface, containing all
- // 255 pixels.
- uint8_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = 255;
- }
-
- {
- // Write the buffer to successive rows until every row of the surface
- // has been written. We place the start column beyond the end of the row,
- // which will prevent us from writing anything, so we check that the
- // generated image is entirely 0.
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0), [&]{
- return aSink->WriteBuffer(buffer, 100, 100);
- });
- }
-
- ResetForNextPass(aSink);
-
- {
- // Write the buffer to successive rows until every row of the surface
- // has been written. We use column 50 as the start column, but we still
- // write the buffer, which means we overflow the right edge of the surface
- // by 50 pixels. We check that the left half of the generated image is
- // 0 and the right half is 255.
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100), [&]{
- return aSink->WriteBuffer(buffer, 50, 100);
- });
- }
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWriteBufferPartialRowBufferOverflow)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Create a buffer twice as large as a row of the surface. The first half
- // (which is as large as a row of the image) will contain 255 pixels,
- // while the second half will contain 128 pixels.
- uint8_t buffer[200];
- for (int i = 0; i < 200; ++i) {
- buffer[i] = i < 100 ? 255 : 128;
- }
-
- {
- // Write the buffer to successive rows until every row of the surface has
- // been written. The buffer extends 100 pixels to the right of a row of
- // the surface, but bounds checking will prevent us from overflowing the
- // buffer. We check that the generated image is entirely 255 since the
- // pixels on the right side of the buffer shouldn't have been written to
- // the surface.
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(0, 0, 100, 100), [&]{
- return aSink->WriteBuffer(buffer, 0, 200);
- });
- }
-
- ResetForNextPass(aSink);
-
- {
- // Write from the buffer to the middle of each row of the surface. That
- // means that the left side of each row should be 0, since we didn't write
- // anything there. A buffer overflow would cause us to write buffer
- // contents into the left side of each row. We check that the generated
- // image is 0 on the left side and 255 on the right.
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100), [&]{
- return aSink->WriteBuffer(buffer, 50, 200);
- });
- }
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWriteBufferFromNullSource)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Calling WriteBuffer() with a null pointer should fail without making any
- // changes to the surface.
- uint8_t* nullBuffer = nullptr;
- WriteState result = aSink->WriteBuffer(nullBuffer);
-
- EXPECT_EQ(WriteState::FAILURE, result);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
- Maybe<SurfaceInvalidRect> invalidRect = aSink->TakeInvalidRect();
- EXPECT_TRUE(invalidRect.isNothing());
-
- // Check that nothing got written to the surface.
- CheckGeneratedPalettedImage(aDecoder, IntRect(0, 0, 0, 0));
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWriteEmptyRow)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- {
- // Write an empty row to each row of the surface. We check that the
- // generated image is entirely 0.
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0), [&]{
- return aSink->WriteEmptyRow();
- });
- }
-
- ResetForNextPass(aSink);
-
- {
- // Write a partial row before we begin calling WriteEmptyRow(). We check
- // that the generated image is entirely 0, which is to be expected since
- // WriteEmptyRow() overwrites the current row even if some data has
- // already been written to it.
- uint32_t count = 0;
- auto result = aSink->WritePixels<uint8_t>([&]() -> NextPixel<uint8_t> {
- if (count == 50) {
- return AsVariant(WriteState::NEED_MORE_DATA);
- }
- ++count;
- return AsVariant(uint8_t(255));
- });
-
- EXPECT_EQ(WriteState::NEED_MORE_DATA, result);
- EXPECT_EQ(50u, count);
- EXPECT_FALSE(aSink->IsSurfaceFinished());
-
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(0, 0, 0, 0), [&]{
- return aSink->WriteEmptyRow();
- });
- }
-
- ResetForNextPass(aSink);
-
- {
- // Create a buffer the same size as one row of the surface, containing all
- // 255 pixels.
- uint8_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = 255;
- }
-
- // Write an empty row to the middle 60 rows of the surface. The first 20
- // and last 20 rows will be 255. (We need to use DoCheckIterativeWrite()
- // here because we need a custom function to check the output, since it
- // can't be described by a simple rect.)
- auto writeFunc = [&](uint32_t aRow) {
- if (aRow < 20 || aRow >= 80) {
- return aSink->WriteBuffer(buffer);
- } else {
- return aSink->WriteEmptyRow();
- }
- };
-
- auto checkFunc = [&]{
- EXPECT_TRUE(PalettedRowsAreSolidColor(aDecoder, 0, 20, 255));
- EXPECT_TRUE(PalettedRowsAreSolidColor(aDecoder, 20, 60, 0));
- EXPECT_TRUE(PalettedRowsAreSolidColor(aDecoder, 80, 20, 255));
- };
-
- DoCheckIterativeWrite(aSink, writeFunc, checkFunc);
- }
- });
-}
-
-TEST(ImageSurfaceSink, PalettedSurfaceSinkWriteUnsafeComputedRow)
-{
- WithPalettedSurfaceSink(IntRect(0, 0, 100, 100),
- [](Decoder* aDecoder, PalettedSurfaceSink* aSink) {
- // Create an all-255 buffer the same size as one row of the surface.
- uint8_t buffer[100];
- for (int i = 0; i < 100; ++i) {
- buffer[i] = 255;
- }
-
- // Write the buffer to successive rows until every row of the surface has
- // been written. We only write to the right half of each row, so we check
- // that the left side of the generated image is 0 and the right side is 255.
- CheckPalettedIterativeWrite(aDecoder, aSink, IntRect(50, 0, 50, 100), [&]{
- return aSink->WriteUnsafeComputedRow<uint8_t>([&](uint8_t* aRow,
- uint32_t aLength) {
- EXPECT_EQ(100u, aLength );
- memcpy(aRow + 50, buffer, 50 * sizeof(uint8_t));
- });
- });
- });
-}
diff --git a/image/test/gtest/animated-with-extra-image-sub-blocks.gif b/image/test/gtest/animated-with-extra-image-sub-blocks.gif
deleted file mode 100644
index a145c814a..000000000
--- a/image/test/gtest/animated-with-extra-image-sub-blocks.gif
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/corrupt-with-bad-bmp-height.ico b/image/test/gtest/corrupt-with-bad-bmp-height.ico
deleted file mode 100644
index ee4a90fcd..000000000
--- a/image/test/gtest/corrupt-with-bad-bmp-height.ico
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/corrupt-with-bad-bmp-width.ico b/image/test/gtest/corrupt-with-bad-bmp-width.ico
deleted file mode 100644
index aa4051cd0..000000000
--- a/image/test/gtest/corrupt-with-bad-bmp-width.ico
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/corrupt.jpg b/image/test/gtest/corrupt.jpg
deleted file mode 100644
index 555a416d7..000000000
--- a/image/test/gtest/corrupt.jpg
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/downscaled.bmp b/image/test/gtest/downscaled.bmp
deleted file mode 100644
index 9e6a29e62..000000000
--- a/image/test/gtest/downscaled.bmp
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/downscaled.gif b/image/test/gtest/downscaled.gif
deleted file mode 100644
index ff9a20bcd..000000000
--- a/image/test/gtest/downscaled.gif
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/downscaled.ico b/image/test/gtest/downscaled.ico
deleted file mode 100644
index ee112af0a..000000000
--- a/image/test/gtest/downscaled.ico
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/downscaled.icon b/image/test/gtest/downscaled.icon
deleted file mode 100644
index 19785f5dc..000000000
--- a/image/test/gtest/downscaled.icon
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/downscaled.jpg b/image/test/gtest/downscaled.jpg
deleted file mode 100644
index 5a4b3cd03..000000000
--- a/image/test/gtest/downscaled.jpg
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/downscaled.png b/image/test/gtest/downscaled.png
deleted file mode 100644
index b71b4652d..000000000
--- a/image/test/gtest/downscaled.png
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/first-frame-green.gif b/image/test/gtest/first-frame-green.gif
deleted file mode 100644
index cd3c7d3db..000000000
--- a/image/test/gtest/first-frame-green.gif
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/first-frame-green.png b/image/test/gtest/first-frame-green.png
deleted file mode 100644
index 115f035d8..000000000
--- a/image/test/gtest/first-frame-green.png
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/first-frame-padding.gif b/image/test/gtest/first-frame-padding.gif
deleted file mode 100644
index e6d7c4932..000000000
--- a/image/test/gtest/first-frame-padding.gif
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/green-1x1-truncated.gif b/image/test/gtest/green-1x1-truncated.gif
deleted file mode 100644
index 0829f9694..000000000
--- a/image/test/gtest/green-1x1-truncated.gif
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/green.bmp b/image/test/gtest/green.bmp
deleted file mode 100644
index f79dd672a..000000000
--- a/image/test/gtest/green.bmp
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/green.gif b/image/test/gtest/green.gif
deleted file mode 100644
index ef215dfc9..000000000
--- a/image/test/gtest/green.gif
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/green.ico b/image/test/gtest/green.ico
deleted file mode 100644
index c5dfa8b53..000000000
--- a/image/test/gtest/green.ico
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/green.icon b/image/test/gtest/green.icon
deleted file mode 100644
index c74e62fee..000000000
--- a/image/test/gtest/green.icon
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/green.jpg b/image/test/gtest/green.jpg
deleted file mode 100644
index 48c454d27..000000000
--- a/image/test/gtest/green.jpg
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/green.png b/image/test/gtest/green.png
deleted file mode 100644
index 7df25f33b..000000000
--- a/image/test/gtest/green.png
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/invalid-truncated-metadata.bmp b/image/test/gtest/invalid-truncated-metadata.bmp
deleted file mode 100644
index 228c5c999..000000000
--- a/image/test/gtest/invalid-truncated-metadata.bmp
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/moz.build b/image/test/gtest/moz.build
deleted file mode 100644
index 3548eaecc..000000000
--- a/image/test/gtest/moz.build
+++ /dev/null
@@ -1,79 +0,0 @@
-# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
-# vim: set filetype=python:
-# This Source Code Form is subject to the terms of the Mozilla Public
-# License, v. 2.0. If a copy of the MPL was not distributed with this
-# file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
-Library('imagetest')
-
-UNIFIED_SOURCES = [
- 'Common.cpp',
- 'TestADAM7InterpolatingFilter.cpp',
- 'TestCopyOnWrite.cpp',
- 'TestDecoders.cpp',
- 'TestDecodeToSurface.cpp',
- 'TestDeinterlacingFilter.cpp',
- 'TestLoader.cpp',
- 'TestMetadata.cpp',
- 'TestRemoveFrameRectFilter.cpp',
- 'TestSourceBuffer.cpp',
- 'TestStreamingLexer.cpp',
- 'TestSurfaceSink.cpp',
-]
-
-if CONFIG['MOZ_ENABLE_SKIA']:
- UNIFIED_SOURCES += [
- 'TestDownscalingFilter.cpp',
- 'TestSurfacePipeIntegration.cpp',
- ]
-
-SOURCES += [
- # Can't be unified because it manipulates the preprocessor environment.
- 'TestDownscalingFilterNoSkia.cpp',
-]
-
-TEST_HARNESS_FILES.gtest += [
- 'animated-with-extra-image-sub-blocks.gif',
- 'corrupt-with-bad-bmp-height.ico',
- 'corrupt-with-bad-bmp-width.ico',
- 'corrupt.jpg',
- 'downscaled.bmp',
- 'downscaled.gif',
- 'downscaled.ico',
- 'downscaled.icon',
- 'downscaled.jpg',
- 'downscaled.png',
- 'first-frame-green.gif',
- 'first-frame-green.png',
- 'first-frame-padding.gif',
- 'green-1x1-truncated.gif',
- 'green.bmp',
- 'green.gif',
- 'green.ico',
- 'green.icon',
- 'green.jpg',
- 'green.png',
- 'invalid-truncated-metadata.bmp',
- 'no-frame-delay.gif',
- 'rle4.bmp',
- 'rle8.bmp',
- 'transparent-ico-with-and-mask.ico',
- 'transparent-if-within-ico.bmp',
- 'transparent.gif',
- 'transparent.png',
-]
-
-include('/ipc/chromium/chromium-config.mozbuild')
-
-LOCAL_INCLUDES += [
- '/dom/base',
- '/gfx/2d',
- '/image',
-]
-
-LOCAL_INCLUDES += CONFIG['SKIA_INCLUDES']
-
-FINAL_LIBRARY = 'xul-gtest'
-
-if CONFIG['GNU_CXX']:
- CXXFLAGS += ['-Wno-error=shadow']
diff --git a/image/test/gtest/no-frame-delay.gif b/image/test/gtest/no-frame-delay.gif
deleted file mode 100644
index 1c50b6743..000000000
--- a/image/test/gtest/no-frame-delay.gif
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/rle4.bmp b/image/test/gtest/rle4.bmp
deleted file mode 100644
index 78a092787..000000000
--- a/image/test/gtest/rle4.bmp
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/rle8.bmp b/image/test/gtest/rle8.bmp
deleted file mode 100644
index bd793b6b6..000000000
--- a/image/test/gtest/rle8.bmp
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/transparent-ico-with-and-mask.ico b/image/test/gtest/transparent-ico-with-and-mask.ico
deleted file mode 100644
index ab0dc4bce..000000000
--- a/image/test/gtest/transparent-ico-with-and-mask.ico
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/transparent-if-within-ico.bmp b/image/test/gtest/transparent-if-within-ico.bmp
deleted file mode 100644
index 4dc04c181..000000000
--- a/image/test/gtest/transparent-if-within-ico.bmp
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/transparent.gif b/image/test/gtest/transparent.gif
deleted file mode 100644
index 48f5c7caf..000000000
--- a/image/test/gtest/transparent.gif
+++ /dev/null
Binary files differ
diff --git a/image/test/gtest/transparent.png b/image/test/gtest/transparent.png
deleted file mode 100644
index fc8002053..000000000
--- a/image/test/gtest/transparent.png
+++ /dev/null
Binary files differ