summaryrefslogtreecommitdiffstats
path: root/image/test/gtest/Common.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'image/test/gtest/Common.cpp')
-rw-r--r--image/test/gtest/Common.cpp673
1 files changed, 673 insertions, 0 deletions
diff --git a/image/test/gtest/Common.cpp b/image/test/gtest/Common.cpp
new file mode 100644
index 000000000..5a24bbb14
--- /dev/null
+++ b/image/test/gtest/Common.cpp
@@ -0,0 +1,673 @@
+/* -*- 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