1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 
5 #include "gtest/gtest.h"
6 
7 #include "Common.h"
8 #include "AnimationSurfaceProvider.h"
9 #include "Decoder.h"
10 #include "ImageFactory.h"
11 #include "nsIInputStream.h"
12 #include "RasterImage.h"
13 
14 using namespace mozilla;
15 using namespace mozilla::gfx;
16 using namespace mozilla::image;
17 
CheckFrameAnimatorBlendResults(const ImageTestCase & aTestCase,RasterImage * aImage)18 static void CheckFrameAnimatorBlendResults(const ImageTestCase& aTestCase,
19                                            RasterImage* aImage) {
20   // Allow the animation to actually begin.
21   aImage->IncrementAnimationConsumers();
22 
23   // Initialize for the first frame so we can advance.
24   TimeStamp now = TimeStamp::Now();
25   aImage->RequestRefresh(now);
26 
27   RefPtr<SourceSurface> surface =
28       aImage->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_NONE);
29   ASSERT_TRUE(surface != nullptr);
30 
31   CheckGeneratedSurface(surface, IntRect(0, 0, 50, 50),
32                         BGRAColor::Transparent(),
33                         aTestCase.ChooseColor(BGRAColor::Red()));
34 
35   // Advance to the next/final frame.
36   now = TimeStamp::Now() + TimeDuration::FromMilliseconds(500);
37   aImage->RequestRefresh(now);
38 
39   surface =
40       aImage->GetFrame(imgIContainer::FRAME_CURRENT, imgIContainer::FLAG_NONE);
41   ASSERT_TRUE(surface != nullptr);
42   CheckGeneratedSurface(surface, IntRect(0, 0, 50, 50),
43                         aTestCase.ChooseColor(BGRAColor::Green()),
44                         aTestCase.ChooseColor(BGRAColor::Red()));
45 }
46 
47 template <typename Func>
WithFrameAnimatorDecode(const ImageTestCase & aTestCase,Func aResultChecker)48 static void WithFrameAnimatorDecode(const ImageTestCase& aTestCase,
49                                     Func aResultChecker) {
50   // Create an image.
51   RefPtr<Image> image = ImageFactory::CreateAnonymousImage(
52       nsDependentCString(aTestCase.mMimeType));
53   ASSERT_TRUE(!image->HasError());
54 
55   NotNull<RefPtr<RasterImage>> rasterImage =
56       WrapNotNull(static_cast<RasterImage*>(image.get()));
57 
58   nsCOMPtr<nsIInputStream> inputStream = LoadFile(aTestCase.mPath);
59   ASSERT_TRUE(inputStream != nullptr);
60 
61   // Figure out how much data we have.
62   uint64_t length;
63   nsresult rv = inputStream->Available(&length);
64   ASSERT_TRUE(NS_SUCCEEDED(rv));
65 
66   // Write the data into a SourceBuffer.
67   NotNull<RefPtr<SourceBuffer>> sourceBuffer = WrapNotNull(new SourceBuffer());
68   sourceBuffer->ExpectLength(length);
69   rv = sourceBuffer->AppendFromInputStream(inputStream, length);
70   ASSERT_TRUE(NS_SUCCEEDED(rv));
71   sourceBuffer->Complete(NS_OK);
72 
73   // Create a metadata decoder first, because otherwise RasterImage will get
74   // unhappy about finding out the image is animated during a full decode.
75   DecoderType decoderType = DecoderFactory::GetDecoderType(aTestCase.mMimeType);
76   RefPtr<IDecodingTask> task = DecoderFactory::CreateMetadataDecoder(
77       decoderType, rasterImage, sourceBuffer);
78   ASSERT_TRUE(task != nullptr);
79 
80   // Run the metadata decoder synchronously.
81   task->Run();
82   task = nullptr;
83 
84   // Create an AnimationSurfaceProvider which will manage the decoding process
85   // and make this decoder's output available in the surface cache.
86   DecoderFlags decoderFlags = DefaultDecoderFlags();
87   SurfaceFlags surfaceFlags = aTestCase.mSurfaceFlags;
88   rv = DecoderFactory::CreateAnimationDecoder(
89       decoderType, rasterImage, sourceBuffer, aTestCase.mSize, decoderFlags,
90       surfaceFlags, 0, getter_AddRefs(task));
91   EXPECT_EQ(rv, NS_OK);
92   ASSERT_TRUE(task != nullptr);
93 
94   // Run the full decoder synchronously.
95   task->Run();
96 
97   // Call the lambda to verify the expected results.
98   aResultChecker(rasterImage.get());
99 }
100 
CheckFrameAnimatorBlend(const ImageTestCase & aTestCase)101 static void CheckFrameAnimatorBlend(const ImageTestCase& aTestCase) {
102   WithFrameAnimatorDecode(aTestCase, [&](RasterImage* aImage) {
103     CheckFrameAnimatorBlendResults(aTestCase, aImage);
104   });
105 }
106 
107 class ImageFrameAnimator : public ::testing::Test {
108  protected:
109   AutoInitializeImageLib mInit;
110 };
111 
TEST_F(ImageFrameAnimator,BlendGIFWithFilter)112 TEST_F(ImageFrameAnimator, BlendGIFWithFilter) {
113   CheckFrameAnimatorBlend(BlendAnimatedGIFTestCase());
114 }
115 
TEST_F(ImageFrameAnimator,BlendPNGWithFilter)116 TEST_F(ImageFrameAnimator, BlendPNGWithFilter) {
117   CheckFrameAnimatorBlend(BlendAnimatedPNGTestCase());
118 }
119 
TEST_F(ImageFrameAnimator,BlendWebPWithFilter)120 TEST_F(ImageFrameAnimator, BlendWebPWithFilter) {
121   CheckFrameAnimatorBlend(BlendAnimatedWebPTestCase());
122 }
123