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 #include "gtest/MozGTestBench.h"
7 
8 #include "Common.h"
9 #include "Decoder.h"
10 #include "DecoderFactory.h"
11 #include "IDecodingTask.h"
12 #include "mozilla/RefPtr.h"
13 #include "ProgressTracker.h"
14 #include "SourceBuffer.h"
15 
16 using namespace mozilla;
17 using namespace mozilla::gfx;
18 using namespace mozilla::image;
19 
20 namespace {
21 
CheckDecoderState(const ImageTestCase & aTestCase,image::Decoder * aDecoder,const IntSize & aOutputSize)22 static void CheckDecoderState(const ImageTestCase& aTestCase,
23                               image::Decoder* aDecoder,
24                               const IntSize& aOutputSize) {
25   // image::Decoder should match what we asked for in the MIME type.
26   EXPECT_NE(aDecoder->GetType(), DecoderType::UNKNOWN);
27   EXPECT_EQ(aDecoder->GetType(),
28             DecoderFactory::GetDecoderType(aTestCase.mMimeType));
29 
30   EXPECT_TRUE(aDecoder->GetDecodeDone());
31   EXPECT_FALSE(aDecoder->HasError());
32 
33   // Verify that the decoder made the expected progress.
34   Progress progress = aDecoder->TakeProgress();
35   EXPECT_FALSE(bool(progress & FLAG_HAS_ERROR));
36   EXPECT_FALSE(bool(aTestCase.mFlags & TEST_CASE_HAS_ERROR));
37 
38   EXPECT_TRUE(bool(progress & FLAG_SIZE_AVAILABLE));
39   EXPECT_TRUE(bool(progress & FLAG_DECODE_COMPLETE));
40   EXPECT_TRUE(bool(progress & FLAG_FRAME_COMPLETE));
41   EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_TRANSPARENT),
42             bool(progress & FLAG_HAS_TRANSPARENCY));
43   EXPECT_EQ(bool(aTestCase.mFlags & TEST_CASE_IS_ANIMATED),
44             bool(progress & FLAG_IS_ANIMATED));
45 
46   // The decoder should get the correct size.
47   OrientedIntSize size = aDecoder->Size();
48   EXPECT_EQ(aTestCase.mSize.width, size.width);
49   EXPECT_EQ(aTestCase.mSize.height, size.height);
50 
51   // Get the current frame, which is always the first frame of the image
52   // because CreateAnonymousDecoder() forces a first-frame-only decode.
53   RawAccessFrameRef currentFrame = aDecoder->GetCurrentFrameRef();
54   RefPtr<SourceSurface> surface = currentFrame->GetSourceSurface();
55 
56   // Verify that the resulting surfaces matches our expectations.
57   EXPECT_TRUE(surface->IsDataSourceSurface());
58   EXPECT_TRUE(surface->GetFormat() == SurfaceFormat::OS_RGBX ||
59               surface->GetFormat() == SurfaceFormat::OS_RGBA);
60   EXPECT_EQ(aOutputSize, surface->GetSize());
61 }
62 
63 template <typename Func>
WithSingleChunkDecode(const ImageTestCase & aTestCase,SourceBuffer * aSourceBuffer,const Maybe<IntSize> & aOutputSize,Func aResultChecker)64 static void WithSingleChunkDecode(const ImageTestCase& aTestCase,
65                                   SourceBuffer* aSourceBuffer,
66                                   const Maybe<IntSize>& aOutputSize,
67                                   Func aResultChecker) {
68   auto sourceBuffer = WrapNotNull(RefPtr<SourceBuffer>(aSourceBuffer));
69 
70   // Create a decoder.
71   DecoderType decoderType = DecoderFactory::GetDecoderType(aTestCase.mMimeType);
72   RefPtr<image::Decoder> decoder = DecoderFactory::CreateAnonymousDecoder(
73       decoderType, sourceBuffer, aOutputSize, DecoderFlags::FIRST_FRAME_ONLY,
74       aTestCase.mSurfaceFlags);
75   ASSERT_TRUE(decoder != nullptr);
76   RefPtr<IDecodingTask> task =
77       new AnonymousDecodingTask(WrapNotNull(decoder), /* aResumable */ false);
78 
79   // Run the full decoder synchronously.
80   task->Run();
81 
82   // Call the lambda to verify the expected results.
83   aResultChecker(decoder);
84 }
85 
CheckDecode(const ImageTestCase & aTestCase,SourceBuffer * aSourceBuffer)86 static void CheckDecode(const ImageTestCase& aTestCase,
87                         SourceBuffer* aSourceBuffer) {
88   WithSingleChunkDecode(
89       aTestCase, aSourceBuffer, Nothing(), [&](image::Decoder* aDecoder) {
90         CheckDecoderState(aTestCase, aDecoder, aTestCase.mSize);
91       });
92 }
93 
CheckDownscaleDuringDecode(const ImageTestCase & aTestCase,SourceBuffer * aSourceBuffer)94 static void CheckDownscaleDuringDecode(const ImageTestCase& aTestCase,
95                                        SourceBuffer* aSourceBuffer) {
96   IntSize outputSize(20, 20);
97   WithSingleChunkDecode(aTestCase, aSourceBuffer, Some(outputSize),
98                         [&](image::Decoder* aDecoder) {
99                           CheckDecoderState(aTestCase, aDecoder, outputSize);
100                         });
101 }
102 
103 #define IMAGE_GTEST_BENCH_FIXTURE(test_fixture, test_case) \
104   class test_fixture : public ImageBenchmarkBase {         \
105    protected:                                              \
106     test_fixture() : ImageBenchmarkBase(test_case()) {}    \
107   };
108 
109 #define IMAGE_GTEST_NATIVE_BENCH_F(test_fixture) \
110   MOZ_GTEST_BENCH_F(test_fixture, Native,        \
111                     [this] { CheckDecode(mTestCase, mSourceBuffer); });
112 
113 #define IMAGE_GTEST_DOWNSCALE_BENCH_F(test_fixture)       \
114   MOZ_GTEST_BENCH_F(test_fixture, Downscale, [this] {     \
115     CheckDownscaleDuringDecode(mTestCase, mSourceBuffer); \
116   });
117 
118 #define IMAGE_GTEST_NO_COLOR_MANAGEMENT_BENCH_F(test_fixture)         \
119   MOZ_GTEST_BENCH_F(test_fixture, NoColorManagement, [this] {         \
120     ImageTestCase testCase = mTestCase;                               \
121     testCase.mSurfaceFlags |= SurfaceFlags::NO_COLORSPACE_CONVERSION; \
122     CheckDecode(testCase, mSourceBuffer);                             \
123   });
124 
125 #define IMAGE_GTEST_NO_PREMULTIPLY_BENCH_F(test_fixture)          \
126   MOZ_GTEST_BENCH_F(test_fixture, NoPremultiplyAlpha, [this] {    \
127     ImageTestCase testCase = mTestCase;                           \
128     testCase.mSurfaceFlags |= SurfaceFlags::NO_PREMULTIPLY_ALPHA; \
129     CheckDecode(testCase, mSourceBuffer);                         \
130   });
131 
132 #define IMAGE_GTEST_BENCH_F(type, test)                            \
133   IMAGE_GTEST_BENCH_FIXTURE(ImageDecodersPerf_##type##_##test,     \
134                             Perf##test##type##TestCase)            \
135   IMAGE_GTEST_NATIVE_BENCH_F(ImageDecodersPerf_##type##_##test)    \
136   IMAGE_GTEST_DOWNSCALE_BENCH_F(ImageDecodersPerf_##type##_##test) \
137   IMAGE_GTEST_NO_COLOR_MANAGEMENT_BENCH_F(ImageDecodersPerf_##type##_##test)
138 
139 #define IMAGE_GTEST_BENCH_ALPHA_F(type, test) \
140   IMAGE_GTEST_BENCH_F(type, test)             \
141   IMAGE_GTEST_NO_PREMULTIPLY_BENCH_F(ImageDecodersPerf_##type##_##test)
142 
143 IMAGE_GTEST_BENCH_F(JPG, YCbCr)
144 IMAGE_GTEST_BENCH_F(JPG, Cmyk)
145 IMAGE_GTEST_BENCH_F(JPG, Gray)
146 
147 IMAGE_GTEST_BENCH_F(PNG, Rgb)
148 IMAGE_GTEST_BENCH_F(PNG, Gray)
149 IMAGE_GTEST_BENCH_ALPHA_F(PNG, RgbAlpha)
150 IMAGE_GTEST_BENCH_ALPHA_F(PNG, GrayAlpha)
151 
152 IMAGE_GTEST_BENCH_F(WebP, RgbLossless)
153 IMAGE_GTEST_BENCH_F(WebP, RgbLossy)
154 IMAGE_GTEST_BENCH_ALPHA_F(WebP, RgbAlphaLossless)
155 IMAGE_GTEST_BENCH_ALPHA_F(WebP, RgbAlphaLossy)
156 
157 IMAGE_GTEST_BENCH_F(GIF, Rgb)
158 
159 }  // namespace
160