From 5fbd07b38866b227d8dddd5f00c7d96afe018ff0 Mon Sep 17 00:00:00 2001 From: Andrew Osmond Date: Mon, 17 Sep 2018 15:06:29 -0400 Subject: [PATCH] Bug 1337111 - Part 3. Land groundwork for new blended animation gtests. r=tnikkel --- image/Decoder.h | 1 + image/DecoderFactory.cpp | 10 +---- image/DecoderFactory.h | 2 + image/ImageOps.cpp | 4 +- image/test/gtest/Common.cpp | 18 +++++---- image/test/gtest/Common.h | 65 ++++++++++++++++++++++++++++--- image/test/gtest/TestDecoders.cpp | 2 + image/test/gtest/TestMetadata.cpp | 1 + 8 files changed, 80 insertions(+), 23 deletions(-) diff --git a/image/Decoder.h b/image/Decoder.h index 1c764ce42c31..cbda8537055c 100644 --- a/image/Decoder.h +++ b/image/Decoder.h @@ -453,6 +453,7 @@ public: protected: friend class AutoRecordDecoderTelemetry; + friend class DecoderTestHelper; friend class nsICODecoder; friend class PalettedSurfaceSink; friend class SurfaceSink; diff --git a/image/DecoderFactory.cpp b/image/DecoderFactory.cpp index 2383c3901cf9..3cf45bc0d6ac 100644 --- a/image/DecoderFactory.cpp +++ b/image/DecoderFactory.cpp @@ -332,6 +332,7 @@ DecoderFactory::CreateDecoderForICOResource(DecoderType aType, DecoderFactory::CreateAnonymousDecoder(DecoderType aType, NotNull aSourceBuffer, const Maybe& aOutputSize, + DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags) { if (aType == DecoderType::UNKNOWN) { @@ -350,14 +351,7 @@ DecoderFactory::CreateAnonymousDecoder(DecoderType aType, // or do any other expensive work that might be wasted. DecoderFlags decoderFlags = DecoderFlags::IMAGE_IS_TRANSIENT; - // Without an image, the decoder can't store anything in the SurfaceCache, so - // callers will only be able to retrieve the most recent frame via - // Decoder::GetCurrentFrame(). That means that anonymous decoders should - // always be first-frame-only decoders, because nobody ever wants the *last* - // frame. - decoderFlags |= DecoderFlags::FIRST_FRAME_ONLY; - - decoder->SetDecoderFlags(decoderFlags); + decoder->SetDecoderFlags(aDecoderFlags | decoderFlags); decoder->SetSurfaceFlags(aSurfaceFlags); // Set an output size for downscale-during-decode if requested. diff --git a/image/DecoderFactory.h b/image/DecoderFactory.h index b9bbbcb21704..488d644a31c3 100644 --- a/image/DecoderFactory.h +++ b/image/DecoderFactory.h @@ -177,6 +177,7 @@ public: * smaller than the intrinsic size, the decoder will * downscale the image. If Nothing(), the output size will * be the intrinsic size. + * @param aDecoderFlags Flags specifying the behavior of this decoder. * @param aSurfaceFlags Flags specifying the type of output this decoder * should produce. */ @@ -184,6 +185,7 @@ public: CreateAnonymousDecoder(DecoderType aType, NotNull aSourceBuffer, const Maybe& aOutputSize, + DecoderFlags aDecoderFlags, SurfaceFlags aSurfaceFlags); /** diff --git a/image/ImageOps.cpp b/image/ImageOps.cpp index 9d63e8d87575..a4a5561fa3af 100644 --- a/image/ImageOps.cpp +++ b/image/ImageOps.cpp @@ -225,7 +225,9 @@ ImageOps::DecodeToSurface(ImageBuffer* aBuffer, RefPtr decoder = DecoderFactory::CreateAnonymousDecoder(decoderType, WrapNotNull(sourceBuffer), - aSize, ToSurfaceFlags(aFlags)); + aSize, + DecoderFlags::FIRST_FRAME_ONLY, + ToSurfaceFlags(aFlags)); if (!decoder) { return nullptr; } diff --git a/image/test/gtest/Common.cpp b/image/test/gtest/Common.cpp index 6845cf6ae9b5..582a71bbce3c 100644 --- a/image/test/gtest/Common.cpp +++ b/image/test/gtest/Common.cpp @@ -195,20 +195,21 @@ RectIsSolidColor(SourceSurface* aSurface, uint8_t* data = mapping.GetData(); ASSERT_TRUE_OR_RETURN(data != nullptr, false); + BGRAColor pmColor = aColor.Premultiply(); int32_t rowLength = mapping.GetStride(); 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); + ASSERT_LE_OR_RETURN(abs(pmColor.mBlue - data[i + 0]), aFuzz, false); + ASSERT_LE_OR_RETURN(abs(pmColor.mGreen - data[i + 1]), aFuzz, false); + ASSERT_LE_OR_RETURN(abs(pmColor.mRed - data[i + 2]), aFuzz, false); + ASSERT_LE_OR_RETURN(abs(pmColor.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); + ASSERT_EQ_OR_RETURN(pmColor.mBlue, data[i + 0], false); + ASSERT_EQ_OR_RETURN(pmColor.mGreen, data[i + 1], false); + ASSERT_EQ_OR_RETURN(pmColor.mRed, data[i + 2], false); + ASSERT_EQ_OR_RETURN(pmColor.mAlpha, data[i + 3], false); } } } @@ -300,6 +301,7 @@ CreateTrivialDecoder() auto sourceBuffer = MakeNotNull>(); RefPtr decoder = DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(), + DefaultDecoderFlags(), DefaultSurfaceFlags()); return decoder.forget(); } diff --git a/image/test/gtest/Common.h b/image/test/gtest/Common.h index 542629cc1718..9efcb1fb2bae 100644 --- a/image/test/gtest/Common.h +++ b/image/test/gtest/Common.h @@ -10,6 +10,7 @@ #include "gtest/gtest.h" +#include "mozilla/Attributes.h" #include "mozilla/Maybe.h" #include "mozilla/UniquePtr.h" #include "mozilla/gfx/2D.h" @@ -75,11 +76,12 @@ struct BGRAColor { BGRAColor() : BGRAColor(0, 0, 0, 0) { } - BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha) + BGRAColor(uint8_t aBlue, uint8_t aGreen, uint8_t aRed, uint8_t aAlpha, bool aPremultiplied = false) : mBlue(aBlue) , mGreen(aGreen) , mRed(aRed) , mAlpha(aAlpha) + , mPremultiplied(aPremultiplied) { } static BGRAColor Green() { return BGRAColor(0x00, 0xFF, 0x00, 0xFF); } @@ -87,12 +89,30 @@ struct BGRAColor 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); } + BGRAColor Premultiply() const + { + if (!mPremultiplied) { + return BGRAColor(gfxPreMultiply(mBlue, mAlpha), + gfxPreMultiply(mGreen, mAlpha), + gfxPreMultiply(mRed, mAlpha), + mAlpha, + true); + } + return *this; + } + + uint32_t AsPixel() const { + if (!mPremultiplied) { + return gfxPackedPixel(mAlpha, mRed, mGreen, mBlue); + } + return gfxPackedPixelNoPreMultiply(mAlpha, mRed, mGreen, mBlue); + } uint8_t mBlue; uint8_t mGreen; uint8_t mRed; uint8_t mAlpha; + bool mPremultiplied; }; @@ -241,7 +261,7 @@ already_AddRefed CreateTrivialDecoder(); * @param aConfigs The configuration for the pipeline. */ template -void WithFilterPipeline(Decoder* aDecoder, Func aFunc, const Configs&... aConfigs) +void WithFilterPipeline(Decoder* aDecoder, Func aFunc, bool aFinish, const Configs&... aConfigs) { auto pipe = MakeUnique::Type>(); nsresult rv = pipe->Configure(aConfigs...); @@ -249,12 +269,20 @@ void WithFilterPipeline(Decoder* aDecoder, Func aFunc, const Configs&... aConfig aFunc(aDecoder, pipe.get()); - RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef(); - if (currentFrame) { - currentFrame->Finish(); + if (aFinish) { + RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef(); + if (currentFrame) { + currentFrame->Finish(); + } } } +template +void WithFilterPipeline(Decoder* aDecoder, Func aFunc, const Configs&... aConfigs) +{ + WithFilterPipeline(aDecoder, aFunc, true, aConfigs...); +} + /** * Creates a pipeline of SurfaceFilters from a list of Config structs and * asserts that configuring it fails. Cleanup of any allocated surfaces is @@ -369,6 +397,31 @@ void CheckPalettedWritePixels(Decoder* aDecoder, const Maybe& aOutputWriteRect = Nothing(), uint8_t aFuzz = 0); +/////////////////////////////////////////////////////////////////////////////// +// Decoder Helpers +/////////////////////////////////////////////////////////////////////////////// + +// Friend class of Decoder to access internals for tests. +class MOZ_STACK_CLASS DecoderTestHelper final +{ +public: + explicit DecoderTestHelper(Decoder* aDecoder) + : mDecoder(aDecoder) + { } + + void PostIsAnimated(FrameTimeout aTimeout) + { + mDecoder->PostIsAnimated(aTimeout); + } + + void PostFrameStop(Opacity aOpacity) + { + mDecoder->PostFrameStop(aOpacity); + } + +private: + Decoder* mDecoder; +}; /////////////////////////////////////////////////////////////////////////////// // Test Data diff --git a/image/test/gtest/TestDecoders.cpp b/image/test/gtest/TestDecoders.cpp index 90e7c9cfb5ac..b43da5c66136 100644 --- a/image/test/gtest/TestDecoders.cpp +++ b/image/test/gtest/TestDecoders.cpp @@ -115,6 +115,7 @@ void WithSingleChunkDecode(const ImageTestCase& aTestCase, DecoderFactory::GetDecoderType(aTestCase.mMimeType); RefPtr decoder = DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, aOutputSize, + DecoderFlags::FIRST_FRAME_ONLY, DefaultSurfaceFlags()); ASSERT_TRUE(decoder != nullptr); RefPtr task = new AnonymousDecodingTask(WrapNotNull(decoder)); @@ -152,6 +153,7 @@ CheckDecoderMultiChunk(const ImageTestCase& aTestCase) DecoderFactory::GetDecoderType(aTestCase.mMimeType); RefPtr decoder = DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(), + DecoderFlags::FIRST_FRAME_ONLY, DefaultSurfaceFlags()); ASSERT_TRUE(decoder != nullptr); RefPtr task = new AnonymousDecodingTask(WrapNotNull(decoder)); diff --git a/image/test/gtest/TestMetadata.cpp b/image/test/gtest/TestMetadata.cpp index be36fe0a5637..67a218f84a6c 100644 --- a/image/test/gtest/TestMetadata.cpp +++ b/image/test/gtest/TestMetadata.cpp @@ -108,6 +108,7 @@ CheckMetadata(const ImageTestCase& aTestCase, // Create a full decoder, so we can compare the result. decoder = DecoderFactory::CreateAnonymousDecoder(decoderType, sourceBuffer, Nothing(), + DecoderFlags::FIRST_FRAME_ONLY, DefaultSurfaceFlags()); ASSERT_TRUE(decoder != nullptr); task = new AnonymousDecodingTask(WrapNotNull(decoder));