/src/mozilla-central/image/test/gtest/TestDecodeToSurface.cpp
Line | Count | Source (jump to first uncovered line) |
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 "imgIContainer.h" |
9 | | #include "imgITools.h" |
10 | | #include "ImageOps.h" |
11 | | #include "mozilla/gfx/2D.h" |
12 | | #include "nsComponentManagerUtils.h" |
13 | | #include "nsCOMPtr.h" |
14 | | #include "nsIInputStream.h" |
15 | | #include "nsIRunnable.h" |
16 | | #include "nsIThread.h" |
17 | | #include "mozilla/RefPtr.h" |
18 | | #include "nsString.h" |
19 | | #include "nsThreadUtils.h" |
20 | | |
21 | | using namespace mozilla; |
22 | | using namespace mozilla::gfx; |
23 | | using namespace mozilla::image; |
24 | | |
25 | | class DecodeToSurfaceRunnable : public Runnable |
26 | | { |
27 | | public: |
28 | | DecodeToSurfaceRunnable(RefPtr<SourceSurface>& aSurface, |
29 | | nsIInputStream* aInputStream, |
30 | | ImageOps::ImageBuffer* aImageBuffer, |
31 | | const ImageTestCase& aTestCase) |
32 | | : mozilla::Runnable("DecodeToSurfaceRunnable") |
33 | | , mSurface(aSurface) |
34 | | , mInputStream(aInputStream) |
35 | | , mImageBuffer(aImageBuffer) |
36 | | , mTestCase(aTestCase) |
37 | 0 | { } |
38 | | |
39 | | NS_IMETHOD Run() override |
40 | 0 | { |
41 | 0 | Go(); |
42 | 0 | return NS_OK; |
43 | 0 | } |
44 | | |
45 | | void Go() |
46 | 0 | { |
47 | 0 | Maybe<IntSize> outputSize; |
48 | 0 | if (mTestCase.mOutputSize != mTestCase.mSize) { |
49 | 0 | outputSize.emplace(mTestCase.mOutputSize); |
50 | 0 | } |
51 | 0 |
|
52 | 0 | if (mImageBuffer) { |
53 | 0 | mSurface = |
54 | 0 | ImageOps::DecodeToSurface(mImageBuffer, |
55 | 0 | nsDependentCString(mTestCase.mMimeType), |
56 | 0 | imgIContainer::DECODE_FLAGS_DEFAULT, |
57 | 0 | outputSize); |
58 | 0 | } else { |
59 | 0 | mSurface = |
60 | 0 | ImageOps::DecodeToSurface(mInputStream.forget(), |
61 | 0 | nsDependentCString(mTestCase.mMimeType), |
62 | 0 | imgIContainer::DECODE_FLAGS_DEFAULT, |
63 | 0 | outputSize); |
64 | 0 | } |
65 | 0 | ASSERT_TRUE(mSurface != nullptr); |
66 | 0 |
|
67 | 0 | EXPECT_TRUE(mSurface->IsDataSourceSurface()); |
68 | 0 | EXPECT_TRUE(mSurface->GetFormat() == SurfaceFormat::B8G8R8X8 || |
69 | 0 | mSurface->GetFormat() == SurfaceFormat::B8G8R8A8); |
70 | 0 |
|
71 | 0 | if (outputSize) { |
72 | 0 | EXPECT_EQ(*outputSize, mSurface->GetSize()); |
73 | 0 | } else { |
74 | 0 | EXPECT_EQ(mTestCase.mSize, mSurface->GetSize()); |
75 | 0 | } |
76 | 0 |
|
77 | 0 | EXPECT_TRUE(IsSolidColor(mSurface, BGRAColor::Green(), |
78 | 0 | mTestCase.mFlags & TEST_CASE_IS_FUZZY ? 1 : 0)); |
79 | 0 | } |
80 | | |
81 | | private: |
82 | | RefPtr<SourceSurface>& mSurface; |
83 | | nsCOMPtr<nsIInputStream> mInputStream; |
84 | | RefPtr<ImageOps::ImageBuffer> mImageBuffer; |
85 | | ImageTestCase mTestCase; |
86 | | }; |
87 | | |
88 | | static void |
89 | | RunDecodeToSurface(const ImageTestCase& aTestCase, |
90 | | ImageOps::ImageBuffer* aImageBuffer = nullptr) |
91 | 0 | { |
92 | 0 | nsCOMPtr<nsIInputStream> inputStream; |
93 | 0 | if (!aImageBuffer) { |
94 | 0 | inputStream = LoadFile(aTestCase.mPath); |
95 | 0 | ASSERT_TRUE(inputStream != nullptr); |
96 | 0 | } |
97 | 0 |
|
98 | 0 | nsCOMPtr<nsIThread> thread; |
99 | 0 | nsresult rv = |
100 | 0 | NS_NewNamedThread("DecodeToSurface", getter_AddRefs(thread), nullptr); |
101 | 0 | ASSERT_TRUE(NS_SUCCEEDED(rv)); |
102 | 0 |
|
103 | 0 | // We run the DecodeToSurface tests off-main-thread to ensure that |
104 | 0 | // DecodeToSurface doesn't require any main-thread-only code. |
105 | 0 | RefPtr<SourceSurface> surface; |
106 | 0 | nsCOMPtr<nsIRunnable> runnable = |
107 | 0 | new DecodeToSurfaceRunnable(surface, inputStream, aImageBuffer, aTestCase); |
108 | 0 | thread->Dispatch(runnable, nsIThread::DISPATCH_SYNC); |
109 | 0 |
|
110 | 0 | thread->Shutdown(); |
111 | 0 |
|
112 | 0 | // Explicitly release the SourceSurface on the main thread. |
113 | 0 | surface = nullptr; |
114 | 0 | } |
115 | | |
116 | | class ImageDecodeToSurface : public ::testing::Test |
117 | | { |
118 | | protected: |
119 | | AutoInitializeImageLib mInit; |
120 | | }; |
121 | | |
122 | 0 | TEST_F(ImageDecodeToSurface, PNG) { RunDecodeToSurface(GreenPNGTestCase()); } |
123 | 0 | TEST_F(ImageDecodeToSurface, GIF) { RunDecodeToSurface(GreenGIFTestCase()); } |
124 | 0 | TEST_F(ImageDecodeToSurface, JPG) { RunDecodeToSurface(GreenJPGTestCase()); } |
125 | 0 | TEST_F(ImageDecodeToSurface, BMP) { RunDecodeToSurface(GreenBMPTestCase()); } |
126 | 0 | TEST_F(ImageDecodeToSurface, ICO) { RunDecodeToSurface(GreenICOTestCase()); } |
127 | 0 | TEST_F(ImageDecodeToSurface, Icon) { RunDecodeToSurface(GreenIconTestCase()); } |
128 | | |
129 | | TEST_F(ImageDecodeToSurface, AnimatedGIF) |
130 | 0 | { |
131 | 0 | RunDecodeToSurface(GreenFirstFrameAnimatedGIFTestCase()); |
132 | 0 | } |
133 | | |
134 | | TEST_F(ImageDecodeToSurface, AnimatedPNG) |
135 | 0 | { |
136 | 0 | RunDecodeToSurface(GreenFirstFrameAnimatedPNGTestCase()); |
137 | 0 | } |
138 | | |
139 | | TEST_F(ImageDecodeToSurface, Corrupt) |
140 | 0 | { |
141 | 0 | ImageTestCase testCase = CorruptTestCase(); |
142 | 0 |
|
143 | 0 | nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath); |
144 | 0 | ASSERT_TRUE(inputStream != nullptr); |
145 | 0 |
|
146 | 0 | RefPtr<SourceSurface> surface = |
147 | 0 | ImageOps::DecodeToSurface(inputStream.forget(), |
148 | 0 | nsDependentCString(testCase.mMimeType), |
149 | 0 | imgIContainer::DECODE_FLAGS_DEFAULT); |
150 | 0 | EXPECT_TRUE(surface == nullptr); |
151 | 0 | } |
152 | | |
153 | | TEST_F(ImageDecodeToSurface, ICOMultipleSizes) |
154 | 0 | { |
155 | 0 | ImageTestCase testCase = GreenMultipleSizesICOTestCase(); |
156 | 0 |
|
157 | 0 | nsCOMPtr<nsIInputStream> inputStream = LoadFile(testCase.mPath); |
158 | 0 | ASSERT_TRUE(inputStream != nullptr); |
159 | 0 |
|
160 | 0 | RefPtr<ImageOps::ImageBuffer> buffer = |
161 | 0 | ImageOps::CreateImageBuffer(inputStream.forget()); |
162 | 0 | ASSERT_TRUE(buffer != nullptr); |
163 | 0 |
|
164 | 0 | ImageMetadata metadata; |
165 | 0 | nsresult rv = ImageOps::DecodeMetadata(buffer, |
166 | 0 | nsDependentCString(testCase.mMimeType), |
167 | 0 | metadata); |
168 | 0 | EXPECT_TRUE(NS_SUCCEEDED(rv)); |
169 | 0 | ASSERT_TRUE(metadata.HasSize()); |
170 | 0 | EXPECT_EQ(testCase.mSize, metadata.GetSize()); |
171 | 0 |
|
172 | 0 | const nsTArray<IntSize>& nativeSizes = metadata.GetNativeSizes(); |
173 | 0 | ASSERT_EQ(6u, nativeSizes.Length()); |
174 | 0 |
|
175 | 0 | IntSize expectedSizes[] = { |
176 | 0 | IntSize(16, 16), |
177 | 0 | IntSize(32, 32), |
178 | 0 | IntSize(64, 64), |
179 | 0 | IntSize(128, 128), |
180 | 0 | IntSize(256, 256), |
181 | 0 | IntSize(256, 128), |
182 | 0 | }; |
183 | 0 |
|
184 | 0 | for (int i = 0; i < 6; ++i) { |
185 | 0 | EXPECT_EQ(expectedSizes[i], nativeSizes[i]); |
186 | 0 |
|
187 | 0 | // Request decoding at native size |
188 | 0 | testCase.mOutputSize = nativeSizes[i]; |
189 | 0 | RunDecodeToSurface(testCase, buffer); |
190 | 0 | } |
191 | 0 | } |