OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "platform/image-decoders/png/PNGImageDecoder.h" | |
6 | |
7 #include "platform/image-decoders/ImageDecoderTestHelpers.h" | |
8 #include "testing/gtest/include/gtest/gtest.h" | |
9 #include <memory> | |
10 | |
11 namespace blink { | |
12 | |
13 namespace { | |
14 | |
15 std::unique_ptr<ImageDecoder> createDecoder(ImageDecoder::AlphaOption alphaOptio n) | |
16 { | |
17 return wrapUnique(new PNGImageDecoder(alphaOption, | |
18 ImageDecoder::GammaAndColorProfileAppl ied, | |
19 ImageDecoder::noDecodedImageByteLimit) ); | |
20 } | |
21 | |
22 std::unique_ptr<ImageDecoder> createDecoder() | |
23 { | |
24 return createDecoder(ImageDecoder::AlphaNotPremultiplied); | |
25 } | |
26 | |
27 std::unique_ptr<ImageDecoder> createDecoderWithPngData(const char* pngFile) | |
28 { | |
29 auto decoder = createDecoder(); | |
30 auto data = readFile(pngFile); | |
31 EXPECT_FALSE(data->isEmpty()); | |
32 decoder->setData(data.get(), true); | |
33 return decoder; | |
34 } | |
35 | |
36 void testSize(const char* pngFile, IntSize expectedSize) | |
37 { | |
38 auto decoder = createDecoderWithPngData(pngFile); | |
39 EXPECT_TRUE(decoder->isSizeAvailable()); | |
40 EXPECT_EQ(expectedSize, decoder->size()); | |
41 } | |
42 | |
43 void testRepetitionCount(const char* pngFile, int expectedRepetitionCount) | |
44 { | |
45 auto decoder = createDecoderWithPngData(pngFile); | |
46 // Decode frame count should see the number of repetitions as well. | |
47 decoder->frameCount(); | |
48 EXPECT_FALSE(decoder->failed()); | |
49 EXPECT_EQ(expectedRepetitionCount, decoder->repetitionCount()); | |
50 } | |
51 | |
52 // Test whether querying for the size of the image works if we present the | |
53 // data byte by byte. | |
54 void testSizeByteByByte(const char *pngFile, size_t bytesNeededToDecodeSize, | |
55 IntSize expectedSize) | |
56 { | |
57 auto decoder = createDecoder(); | |
58 auto data = readFile(pngFile); | |
59 ASSERT_FALSE(data->isEmpty()); | |
60 ASSERT_LT(bytesNeededToDecodeSize, data->size()); | |
61 | |
62 for (size_t length = 1; length <= bytesNeededToDecodeSize; length++) { | |
63 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), | |
64 length); | |
65 decoder->setData(tempData.get(), false); | |
66 | |
67 if (length < bytesNeededToDecodeSize) { | |
68 EXPECT_FALSE(decoder->isSizeAvailable()); | |
69 EXPECT_TRUE(decoder->size().isEmpty()); | |
70 EXPECT_FALSE(decoder->failed()); | |
71 } else { | |
72 EXPECT_TRUE(decoder->isSizeAvailable()); | |
73 EXPECT_EQ(expectedSize, decoder->size()); | |
74 } | |
75 } | |
76 EXPECT_FALSE(decoder->failed()); | |
77 } | |
78 | |
79 struct PublicFrameInfo { | |
80 size_t duration; | |
81 IntRect frameRect; | |
82 ImageFrame::AlphaBlendSource alphaBlend; | |
83 ImageFrame::DisposalMethod disposalMethod; | |
84 }; | |
85 | |
86 // This is the frame data for the following PNG image: | |
87 // /LayoutTests/fast/images/resources/png-animated-idat-part-of-animation.png | |
88 static PublicFrameInfo pngAnimatedFrameInfo[] = { | |
89 {500, {IntPoint(0, 0), IntSize(5, 5)}, ImageFrame::BlendAtopBgcolor, | |
90 ImageFrame::DisposeKeep}, | |
91 {900, {IntPoint(1, 1), IntSize(3, 1)}, ImageFrame::BlendAtopBgcolor, | |
92 ImageFrame::DisposeOverwriteBgcolor}, | |
93 {2000, {IntPoint(1, 2), IntSize(3, 2)}, ImageFrame::BlendAtopPreviousFrame, | |
94 ImageFrame::DisposeKeep}, | |
95 {1500, {IntPoint(1, 2), IntSize(3, 1)}, ImageFrame::BlendAtopBgcolor, | |
96 ImageFrame::DisposeKeep}, | |
97 }; | |
98 | |
99 void compareFrameWithExpectation(const PublicFrameInfo& expected, | |
100 const ImageFrame* frame) | |
101 { | |
102 EXPECT_EQ(expected.duration, frame->duration()); | |
103 EXPECT_EQ(expected.frameRect, frame->originalFrameRect()); | |
104 EXPECT_EQ(expected.disposalMethod, frame->getDisposalMethod()); | |
105 EXPECT_EQ(expected.alphaBlend, frame->getAlphaBlendSource()); | |
106 } | |
107 | |
108 } // Anonymous namespace | |
109 | |
110 // Animated PNG Tests | |
111 | |
112 TEST(AnimatedPNGTests, sizeTest) | |
113 { | |
114 testSize("/LayoutTests/fast/images/resources/png-animated-idat-part-of-anima tion.png", IntSize(5, 5)); | |
115 testSize("/LayoutTests/fast/images/resources/png-animated-idat-not-part-of-a nimation.png", IntSize(227, 35)); | |
116 } | |
117 | |
118 TEST(AnimatedPNGTests, repetitionCountTest) | |
119 { | |
120 testRepetitionCount("/LayoutTests/fast/images/resources/png-animated-idat-pa rt-of-animation.png", 7u); | |
121 testRepetitionCount("/LayoutTests/fast/images/resources/png-animated-idat-no t-part-of-animation.png", cAnimationLoopInfinite); | |
122 } | |
123 | |
124 // Test if the decoded metdata corresponds to the defined expectations | |
125 TEST(AnimatedPNGTests, MetaDataTest) | |
126 { | |
127 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat- part-of-animation.png"; | |
128 constexpr size_t expectedFrameCount = 4; | |
129 | |
130 auto decoder = createDecoderWithPngData(pngFile); | |
131 ASSERT_EQ(expectedFrameCount, decoder->frameCount()); | |
132 for (size_t i = 0; i < expectedFrameCount; i++) | |
133 compareFrameWithExpectation(pngAnimatedFrameInfo[i], | |
134 decoder->frameBufferAtIndex(i)); | |
135 } | |
136 | |
137 TEST(AnimatedPNGTests, ByteByByteSizeAvailable) | |
138 { | |
139 testSizeByteByByte("/LayoutTests/fast/images/resources/png-animated-idat-par t-of-animation.png", | |
140 141u, IntSize(5, 5)); | |
141 testSizeByteByByte("/LayoutTests/fast/images/resources/png-animated-idat-not -part-of-animation.png", | |
142 79u, IntSize(227, 35)); | |
143 } | |
144 | |
145 // Test whether the frame metadata decoding also works when we provide the data | |
146 // byte by byte. This should cover the case when the client does not provide | |
147 // all data at once. At given offsets, we expect frames to become available. | |
148 // This test checks whether that is the case, and if so, if the frame data is | |
149 // equal to what we expected. | |
150 TEST(AnimatedPNGTests, ByteByByteMetaData) | |
151 { | |
152 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat- part-of-animation.png"; | |
153 constexpr size_t expectedFrameCount = 4; | |
154 | |
155 // These are the byte offsets where each frame should have been parsed. | |
156 // It boils down to the offset of the first fcTL / IEND after the last | |
157 // frame data chunk, plus 8 bytes for recognition. | |
158 size_t frameOffsets[expectedFrameCount] = {180, 249, 322, 430}; | |
159 | |
160 auto decoder = createDecoder(); | |
161 auto data = readFile(pngFile); | |
162 ASSERT_FALSE(data->isEmpty()); | |
163 size_t framesParsed = 0; | |
164 | |
165 for (size_t length = 1; length <= frameOffsets[expectedFrameCount - 1]; leng th++) { | |
166 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), | |
167 length); | |
168 decoder->setData(tempData.get(), false); | |
169 EXPECT_FALSE(decoder->failed()); | |
170 | |
171 if (length < frameOffsets[framesParsed]) { | |
172 EXPECT_EQ(framesParsed, decoder->frameCount()); | |
173 } else { | |
174 ASSERT_EQ(framesParsed + 1, decoder->frameCount()); | |
175 compareFrameWithExpectation(pngAnimatedFrameInfo[framesParsed], | |
176 decoder->frameBufferAtIndex(framesParsed )); | |
177 framesParsed++; | |
178 } | |
179 } | |
180 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
181 EXPECT_FALSE(decoder->failed()); | |
182 } | |
183 | |
184 // This tests if the frame count gets set correctly when parsing frameCount | |
185 // fails in one of the parsing queries. | |
186 // | |
187 // First, enough data is provided such that two frames should be registered. | |
188 // The decoder should at this point not be in the failed status. | |
189 // | |
190 // Then, we provide the rest of the data except for the last IEND chunk, but | |
191 // tell the decoder that this is all the data we have. Now, the decoder should | |
192 // be in the failed state since all data is provided but no IEND chunk has been | |
193 // seen. The frame count should be three, since one extra frame should be | |
194 // discovered. The fourth frame should *not* be registered since the reader | |
scroggo_chromium
2016/10/17 15:27:06
This is the natural extension of what we discussed
| |
195 // should not be able to determine where the frame ends. | |
196 TEST(AnimatedPNGTests, FrameCountWithTruncatedData) | |
197 { | |
198 const char* pngFile = "/LayoutTests/fast/images/resources/png-animated-idat- part-of-animation.png"; | |
199 auto decoder = createDecoder(); | |
200 auto data = readFile(pngFile); | |
201 ASSERT_FALSE(data->isEmpty()); | |
202 | |
203 // Parse up to and including the first two frames | |
204 const size_t offsetTwoFrames = 249; | |
205 const size_t expectedFramesAfter249Bytes = 2; | |
206 RefPtr<SharedBuffer> tempData = SharedBuffer::create(data->data(), | |
207 offsetTwoFrames); | |
208 decoder->setData(tempData.get(), false); | |
209 EXPECT_EQ(expectedFramesAfter249Bytes, decoder->frameCount()); | |
210 EXPECT_FALSE(decoder->failed()); | |
211 | |
212 // Provide the rest of the data except for the last IEND chunk. | |
213 const size_t expectedFramesAfterAllExpect12Bytes = 3; | |
214 tempData = SharedBuffer::create(data->data(), data->size() - 12); | |
215 decoder->setData(tempData.get(), true); | |
216 EXPECT_EQ(expectedFramesAfterAllExpect12Bytes, decoder->frameCount()); | |
217 EXPECT_TRUE(decoder->failed()); | |
218 } | |
219 | |
220 | |
221 | |
222 // Static PNG tests | |
223 | |
224 TEST(StaticPNGTests, repetitionCountTest) | |
225 { | |
226 testRepetitionCount("/LayoutTests/fast/images/resources/png-simple.png", | |
227 cAnimationNone); | |
228 } | |
229 | |
230 TEST(StaticPNGTests, sizeTest) | |
231 { | |
232 testSize("/LayoutTests/fast/images/resources/png-simple.png", | |
233 IntSize(111, 29)); | |
234 } | |
235 | |
236 TEST(StaticPNGTests, MetaDataTest) | |
237 { | |
238 const size_t expectedFrameCount = 1; | |
239 const size_t expectedDuration = 0; | |
240 auto decoder = createDecoderWithPngData("/LayoutTests/fast/images/resources/ png-simple.png"); | |
241 EXPECT_EQ(expectedFrameCount, decoder->frameCount()); | |
242 EXPECT_EQ(expectedDuration, decoder->frameDurationAtIndex(0)); | |
243 } | |
244 | |
245 // This test removes two random byets from the IHDR chunk. The decoder should | |
246 // fail on this since all IHDR data is necessary to decode a PNG image. | |
247 TEST(StaticPNGTests, InvalidIHDRChunk) | |
248 { | |
249 const char* pngFile = "//LayoutTests/fast/images/resources/png-simple.png"; | |
250 auto decoder = createDecoder(); | |
251 auto data = readFile(pngFile); | |
252 ASSERT_FALSE(data->isEmpty()); | |
253 | |
254 const size_t offsetHalfwayIHDR = 20; | |
255 // Give the first part of the PNG stream: 8 signature, 8 IHDR indicator | |
256 // and the first four bytes of IHDR content. | |
257 RefPtr<SharedBuffer> invalidData = SharedBuffer::create(data->data(), | |
258 offsetHalfwayIHDR); | |
259 // Omit the 21st and 22nd byte, and append the rest. | |
260 invalidData->append(SharedBuffer::create(data->data() + 22, | |
261 data->size() - 22)); | |
262 ASSERT_EQ(data->size() - 2, invalidData->size()); | |
263 | |
264 decoder->setData(invalidData, true); | |
265 EXPECT_FALSE(decoder->isSizeAvailable()); | |
266 EXPECT_TRUE(decoder->failed()); | |
267 | |
268 } | |
269 }; // namespace blink | |
OLD | NEW |