OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2013 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions are | |
6 * met: | |
7 * | |
8 * * Redistributions of source code must retain the above copyright | |
9 * notice, this list of conditions and the following disclaimer. | |
10 * * Redistributions in binary form must reproduce the above | |
11 * copyright notice, this list of conditions and the following disclaimer | |
12 * in the documentation and/or other materials provided with the | |
13 * distribution. | |
14 * * Neither the name of Google Inc. nor the names of its | |
15 * contributors may be used to endorse or promote products derived from | |
16 * this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
29 */ | |
30 | |
31 #include "config.h" | |
32 | |
33 #include "core/platform/image-decoders/ImageDecoder.h" | |
34 | |
35 #include "wtf/OwnPtr.h" | |
36 #include "wtf/PassOwnPtr.h" | |
37 #include "wtf/Vector.h" | |
38 #include <gtest/gtest.h> | |
39 | |
40 using namespace WebCore; | |
41 | |
42 class TestImageDecoder : public ImageDecoder { | |
43 public: | |
44 TestImageDecoder() | |
45 : ImageDecoder(ImageSource::AlphaNotPremultiplied, ImageSource::GammaAnd
ColorProfileApplied, noDecodedImageByteLimit) | |
46 { | |
47 } | |
48 | |
49 virtual String filenameExtension() const OVERRIDE { return ""; } | |
50 virtual ImageFrame* frameBufferAtIndex(size_t) OVERRIDE { return 0; } | |
51 | |
52 Vector<ImageFrame, 1>& frameBufferCache() | |
53 { | |
54 return m_frameBufferCache; | |
55 } | |
56 | |
57 void resetRequiredPreviousFrames(bool knownOpaque = false) | |
58 { | |
59 for (size_t i = 0; i < m_frameBufferCache.size(); ++i) | |
60 m_frameBufferCache[i].setRequiredPreviousFrameIndex(findRequiredPrev
iousFrame(i, knownOpaque)); | |
61 } | |
62 | |
63 void initFrames(size_t numFrames, unsigned width = 100, unsigned height = 10
0) | |
64 { | |
65 setSize(width, height); | |
66 m_frameBufferCache.resize(numFrames); | |
67 for (size_t i = 0; i < numFrames; ++i) | |
68 m_frameBufferCache[i].setOriginalFrameRect(IntRect(0, 0, width, heig
ht)); | |
69 } | |
70 }; | |
71 | |
72 TEST(ImageDecoderTest, sizeCalculationMayOverflow) | |
73 { | |
74 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
75 EXPECT_FALSE(decoder->setSize(1 << 29, 1)); | |
76 EXPECT_FALSE(decoder->setSize(1, 1 << 29)); | |
77 EXPECT_FALSE(decoder->setSize(1 << 15, 1 << 15)); | |
78 EXPECT_TRUE(decoder->setSize(1 << 28, 1)); | |
79 EXPECT_TRUE(decoder->setSize(1, 1 << 28)); | |
80 EXPECT_TRUE(decoder->setSize(1 << 14, 1 << 14)); | |
81 } | |
82 | |
83 TEST(ImageDecoderTest, requiredPreviousFrameIndex) | |
84 { | |
85 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
86 decoder->initFrames(6); | |
87 Vector<ImageFrame, 1>& frameBuffers = decoder->frameBufferCache(); | |
88 | |
89 frameBuffers[1].setDisposalMethod(ImageFrame::DisposeKeep); | |
90 frameBuffers[2].setDisposalMethod(ImageFrame::DisposeOverwritePrevious); | |
91 frameBuffers[3].setDisposalMethod(ImageFrame::DisposeOverwritePrevious); | |
92 frameBuffers[4].setDisposalMethod(ImageFrame::DisposeKeep); | |
93 | |
94 decoder->resetRequiredPreviousFrames(); | |
95 | |
96 // The first frame doesn't require any previous frame. | |
97 EXPECT_EQ(kNotFound, frameBuffers[0].requiredPreviousFrameIndex()); | |
98 // The previous DisposeNotSpecified frame is required. | |
99 EXPECT_EQ(0u, frameBuffers[1].requiredPreviousFrameIndex()); | |
100 // DisposeKeep is treated as DisposeNotSpecified. | |
101 EXPECT_EQ(1u, frameBuffers[2].requiredPreviousFrameIndex()); | |
102 // Previous DisposeOverwritePrevious frames are skipped. | |
103 EXPECT_EQ(1u, frameBuffers[3].requiredPreviousFrameIndex()); | |
104 EXPECT_EQ(1u, frameBuffers[4].requiredPreviousFrameIndex()); | |
105 EXPECT_EQ(4u, frameBuffers[5].requiredPreviousFrameIndex()); | |
106 } | |
107 | |
108 TEST(ImageDecoderTest, requiredPreviousFrameIndexDisposeOverwriteBgcolor) | |
109 { | |
110 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
111 decoder->initFrames(3); | |
112 Vector<ImageFrame, 1>& frameBuffers = decoder->frameBufferCache(); | |
113 | |
114 // Fully covering DisposeOverwriteBgcolor previous frame resets the starting
state. | |
115 frameBuffers[1].setDisposalMethod(ImageFrame::DisposeOverwriteBgcolor); | |
116 decoder->resetRequiredPreviousFrames(); | |
117 EXPECT_EQ(kNotFound, frameBuffers[2].requiredPreviousFrameIndex()); | |
118 | |
119 // Partially covering DisposeOverwriteBgcolor previous frame is required by
this frame. | |
120 frameBuffers[1].setOriginalFrameRect(IntRect(50, 50, 50, 50)); | |
121 decoder->resetRequiredPreviousFrames(); | |
122 EXPECT_EQ(1u, frameBuffers[2].requiredPreviousFrameIndex()); | |
123 } | |
124 | |
125 TEST(ImageDecoderTest, requiredPreviousFrameIndexForFrame1) | |
126 { | |
127 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
128 decoder->initFrames(2); | |
129 Vector<ImageFrame, 1>& frameBuffers = decoder->frameBufferCache(); | |
130 | |
131 decoder->resetRequiredPreviousFrames(); | |
132 EXPECT_EQ(0u, frameBuffers[1].requiredPreviousFrameIndex()); | |
133 | |
134 // The first frame with DisposeOverwritePrevious or DisposeOverwriteBgcolor | |
135 // resets the starting state. | |
136 frameBuffers[0].setDisposalMethod(ImageFrame::DisposeOverwritePrevious); | |
137 decoder->resetRequiredPreviousFrames(); | |
138 EXPECT_EQ(kNotFound, frameBuffers[1].requiredPreviousFrameIndex()); | |
139 frameBuffers[0].setDisposalMethod(ImageFrame::DisposeOverwriteBgcolor); | |
140 decoder->resetRequiredPreviousFrames(); | |
141 EXPECT_EQ(kNotFound, frameBuffers[1].requiredPreviousFrameIndex()); | |
142 | |
143 // ... even if it partially covers. | |
144 frameBuffers[0].setOriginalFrameRect(IntRect(50, 50, 50, 50)); | |
145 | |
146 frameBuffers[0].setDisposalMethod(ImageFrame::DisposeOverwritePrevious); | |
147 decoder->resetRequiredPreviousFrames(); | |
148 EXPECT_EQ(kNotFound, frameBuffers[1].requiredPreviousFrameIndex()); | |
149 frameBuffers[0].setDisposalMethod(ImageFrame::DisposeOverwriteBgcolor); | |
150 decoder->resetRequiredPreviousFrames(); | |
151 EXPECT_EQ(kNotFound, frameBuffers[1].requiredPreviousFrameIndex()); | |
152 } | |
153 | |
154 TEST(ImageDecoderTest, requiredPreviousFrameIndexBlendAtopBgcolor) | |
155 { | |
156 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
157 decoder->initFrames(3); | |
158 Vector<ImageFrame, 1>& frameBuffers = decoder->frameBufferCache(); | |
159 | |
160 frameBuffers[1].setOriginalFrameRect(IntRect(25, 25, 50, 50)); | |
161 frameBuffers[2].setAlphaBlendSource(ImageFrame::BlendAtopBgcolor); | |
162 | |
163 // A full frame with 'blending method == BlendAtopBgcolor' doesn't depend on
any prior frames. | |
164 for (int disposeMethod = ImageFrame::DisposeNotSpecified; disposeMethod <= I
mageFrame::DisposeOverwritePrevious; ++disposeMethod) { | |
165 frameBuffers[1].setDisposalMethod(static_cast<ImageFrame::DisposalMethod
>(disposeMethod)); | |
166 decoder->resetRequiredPreviousFrames(); | |
167 EXPECT_EQ(kNotFound, frameBuffers[2].requiredPreviousFrameIndex()); | |
168 } | |
169 | |
170 // A non-full frame with 'blending method == BlendAtopBgcolor' does depend o
n a prior frame. | |
171 frameBuffers[2].setOriginalFrameRect(IntRect(50, 50, 50, 50)); | |
172 for (int disposeMethod = ImageFrame::DisposeNotSpecified; disposeMethod <= I
mageFrame::DisposeOverwritePrevious; ++disposeMethod) { | |
173 frameBuffers[1].setDisposalMethod(static_cast<ImageFrame::DisposalMethod
>(disposeMethod)); | |
174 decoder->resetRequiredPreviousFrames(); | |
175 EXPECT_NE(kNotFound, frameBuffers[2].requiredPreviousFrameIndex()); | |
176 } | |
177 } | |
178 | |
179 TEST(ImageDecoderTest, requiredPreviousFrameIndexKnownOpaque) | |
180 { | |
181 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
182 decoder->initFrames(3); | |
183 Vector<ImageFrame, 1>& frameBuffers = decoder->frameBufferCache(); | |
184 | |
185 frameBuffers[1].setOriginalFrameRect(IntRect(25, 25, 50, 50)); | |
186 | |
187 // A full frame that is known to be opaque doesn't depend on any prior frame
s. | |
188 for (int disposeMethod = ImageFrame::DisposeNotSpecified; disposeMethod <= I
mageFrame::DisposeOverwritePrevious; ++disposeMethod) { | |
189 frameBuffers[1].setDisposalMethod(static_cast<ImageFrame::DisposalMethod
>(disposeMethod)); | |
190 decoder->resetRequiredPreviousFrames(true); | |
191 EXPECT_EQ(kNotFound, frameBuffers[2].requiredPreviousFrameIndex()); | |
192 } | |
193 | |
194 // A non-full frame that is known to be opaque does depend on a prior frame. | |
195 frameBuffers[2].setOriginalFrameRect(IntRect(50, 50, 50, 50)); | |
196 for (int disposeMethod = ImageFrame::DisposeNotSpecified; disposeMethod <= I
mageFrame::DisposeOverwritePrevious; ++disposeMethod) { | |
197 frameBuffers[1].setDisposalMethod(static_cast<ImageFrame::DisposalMethod
>(disposeMethod)); | |
198 decoder->resetRequiredPreviousFrames(true); | |
199 EXPECT_NE(kNotFound, frameBuffers[2].requiredPreviousFrameIndex()); | |
200 } | |
201 } | |
202 | |
203 TEST(ImageDecoderTest, clearCacheExceptFrameDoNothing) | |
204 { | |
205 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
206 decoder->clearCacheExceptFrame(0); | |
207 | |
208 // This should not crash. | |
209 decoder->initFrames(20); | |
210 decoder->clearCacheExceptFrame(kNotFound); | |
211 } | |
212 | |
213 TEST(ImageDecoderTest, clearCacheExceptFrameAll) | |
214 { | |
215 const size_t numFrames = 10; | |
216 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
217 decoder->initFrames(numFrames); | |
218 Vector<ImageFrame, 1>& frameBuffers = decoder->frameBufferCache(); | |
219 for (size_t i = 0; i < numFrames; ++i) | |
220 frameBuffers[i].setStatus(i % 2 ? ImageFrame::FramePartial : ImageFrame:
:FrameComplete); | |
221 | |
222 decoder->clearCacheExceptFrame(kNotFound); | |
223 | |
224 for (size_t i = 0; i < numFrames; ++i) { | |
225 SCOPED_TRACE(testing::Message() << i); | |
226 EXPECT_EQ(ImageFrame::FrameEmpty, frameBuffers[i].status()); | |
227 } | |
228 } | |
229 | |
230 TEST(ImageDecoderTest, clearCacheExceptFramePreverveClearExceptFrame) | |
231 { | |
232 const size_t numFrames = 10; | |
233 OwnPtr<TestImageDecoder> decoder(adoptPtr(new TestImageDecoder())); | |
234 decoder->initFrames(numFrames); | |
235 Vector<ImageFrame, 1>& frameBuffers = decoder->frameBufferCache(); | |
236 for (size_t i = 0; i < numFrames; ++i) | |
237 frameBuffers[i].setStatus(ImageFrame::FrameComplete); | |
238 | |
239 decoder->resetRequiredPreviousFrames(); | |
240 decoder->clearCacheExceptFrame(5); | |
241 for (size_t i = 0; i < numFrames; ++i) { | |
242 SCOPED_TRACE(testing::Message() << i); | |
243 if (i == 5) | |
244 EXPECT_EQ(ImageFrame::FrameComplete, frameBuffers[i].status()); | |
245 else | |
246 EXPECT_EQ(ImageFrame::FrameEmpty, frameBuffers[i].status()); | |
247 } | |
248 } | |
OLD | NEW |