зеркало из https://github.com/mozilla/gecko-dev.git
509 строки
19 KiB
C++
509 строки
19 KiB
C++
/* -*- 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, IntSize(600, 600),
|
|
SurfaceFormat::B8G8R8A8, false });
|
|
}
|