2 * Copyright (c) 2013, Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "platform/graphics/BitmapImage.h"
34 #include "platform/SharedBuffer.h"
35 #include "platform/graphics/DeferredImageDecoder.h"
36 #include "platform/graphics/ImageObserver.h"
37 #include "public/platform/Platform.h"
38 #include "public/platform/WebUnitTestSupport.h"
40 #include <gtest/gtest.h>
44 class BitmapImageTest
: public ::testing::Test
{
46 class FakeImageObserver
: public ImageObserver
{
48 FakeImageObserver() : m_lastDecodedSizeChangedDelta(0) { }
50 virtual void decodedSizeChanged(const Image
*, int delta
)
52 m_lastDecodedSizeChangedDelta
= delta
;
54 void didDraw(const Image
*) override
{ }
55 bool shouldPauseAnimation(const Image
*) override
{ return false; }
56 void animationAdvanced(const Image
*) override
{ }
58 virtual void changedInRect(const Image
*, const IntRect
&) { }
60 int m_lastDecodedSizeChangedDelta
;
63 BitmapImageTest() : BitmapImageTest(false) { }
64 BitmapImageTest(bool enableDeferredDecoding
) : m_enableDeferredDecoding(enableDeferredDecoding
) { }
66 static PassRefPtr
<SharedBuffer
> readFile(const char* fileName
)
68 String filePath
= Platform::current()->unitTestSupport()->webKitRootDir();
69 filePath
.append(fileName
);
70 return Platform::current()->unitTestSupport()->readFromFile(filePath
);
73 // Accessors to BitmapImage's protected methods.
74 void destroyDecodedData(bool destroyAll
) { m_image
->destroyDecodedData(destroyAll
); }
75 size_t frameCount() { return m_image
->frameCount(); }
76 void frameAtIndex(size_t index
)
78 m_image
->frameAtIndex(index
);
80 void setCurrentFrame(size_t frame
) { m_image
->m_currentFrame
= frame
; }
81 size_t frameDecodedSize(size_t frame
) { return m_image
->m_frames
[frame
].m_frameBytes
; }
82 size_t decodedFramesCount() const { return m_image
->m_frames
.size(); }
84 void loadImage(const char* fileName
, bool loadAllFrames
= true)
86 RefPtr
<SharedBuffer
> imageData
= readFile(fileName
);
87 ASSERT_TRUE(imageData
.get());
89 m_image
->setData(imageData
, true);
90 EXPECT_EQ(0u, decodedSize());
92 size_t frameCount
= m_image
->frameCount();
94 for (size_t i
= 0; i
< frameCount
; ++i
)
101 // In the context of this test, the following loop will give the correct result, but only because the test
102 // forces all frames to be decoded in loadImage() above. There is no general guarantee that frameDecodedSize()
103 // is up-to-date. Because of how multi frame images (like GIF) work, requesting one frame to be decoded may
104 // require other previous frames to be decoded as well. In those cases frameDecodedSize() wouldn't return the
105 // correct thing for the previous frame because the decoded size wouldn't have propagated upwards to the
106 // BitmapImage frame cache.
108 for (size_t i
= 0; i
< decodedFramesCount(); ++i
)
109 size
+= frameDecodedSize(i
);
113 void advanceAnimation()
115 m_image
->advanceAnimation(0);
118 PassRefPtr
<Image
> imageForDefaultFrame()
120 return m_image
->imageForDefaultFrame();
124 void SetUp() override
126 DeferredImageDecoder::setEnabled(m_enableDeferredDecoding
);
127 m_image
= BitmapImage::create(&m_imageObserver
);
130 FakeImageObserver m_imageObserver
;
131 RefPtr
<BitmapImage
> m_image
;
134 bool m_enableDeferredDecoding
;
137 TEST_F(BitmapImageTest
, destroyDecodedDataExceptCurrentFrame
)
139 loadImage("/LayoutTests/fast/images/resources/animated-10color.gif");
140 size_t totalSize
= decodedSize();
141 size_t frame
= frameCount() / 2;
142 setCurrentFrame(frame
);
143 size_t size
= frameDecodedSize(frame
);
144 destroyDecodedData(false);
145 EXPECT_LT(m_imageObserver
.m_lastDecodedSizeChangedDelta
, 0);
146 EXPECT_GE(m_imageObserver
.m_lastDecodedSizeChangedDelta
, -static_cast<int>(totalSize
- size
));
149 TEST_F(BitmapImageTest
, destroyAllDecodedData
)
151 loadImage("/LayoutTests/fast/images/resources/animated-10color.gif");
152 size_t totalSize
= decodedSize();
153 EXPECT_GT(totalSize
, 0u);
154 destroyDecodedData(true);
155 EXPECT_EQ(-static_cast<int>(totalSize
), m_imageObserver
.m_lastDecodedSizeChangedDelta
);
156 EXPECT_EQ(0u, decodedSize());
159 TEST_F(BitmapImageTest
, maybeAnimated
)
161 loadImage("/LayoutTests/fast/images/resources/gif-loop-count.gif");
162 for (size_t i
= 0; i
< frameCount(); ++i
) {
163 EXPECT_TRUE(m_image
->maybeAnimated());
166 EXPECT_FALSE(m_image
->maybeAnimated());
169 TEST_F(BitmapImageTest
, isAllDataReceived
)
171 RefPtr
<SharedBuffer
> imageData
= readFile("/LayoutTests/fast/images/resources/green.jpg");
172 ASSERT_TRUE(imageData
.get());
174 RefPtr
<BitmapImage
> image
= BitmapImage::create();
175 EXPECT_FALSE(image
->isAllDataReceived());
177 image
->setData(imageData
, false);
178 EXPECT_FALSE(image
->isAllDataReceived());
180 image
->setData(imageData
, true);
181 EXPECT_TRUE(image
->isAllDataReceived());
183 image
->setData(SharedBuffer::create("data", sizeof("data")), false);
184 EXPECT_FALSE(image
->isAllDataReceived());
186 image
->setData(imageData
, true);
187 EXPECT_TRUE(image
->isAllDataReceived());
190 TEST_F(BitmapImageTest
, noColorProfile
)
192 loadImage("/LayoutTests/fast/images/resources/green.jpg");
193 EXPECT_EQ(1u, decodedFramesCount());
194 EXPECT_EQ(1024u, decodedSize());
195 EXPECT_FALSE(m_image
->hasColorProfile());
200 TEST_F(BitmapImageTest
, jpegHasColorProfile
)
202 loadImage("/LayoutTests/fast/images/resources/icc-v2-gbr.jpg");
203 EXPECT_EQ(1u, decodedFramesCount());
204 EXPECT_EQ(227700u, decodedSize());
205 EXPECT_TRUE(m_image
->hasColorProfile());
208 TEST_F(BitmapImageTest
, pngHasColorProfile
)
210 loadImage("/LayoutTests/fast/images/resources/palatted-color-png-gamma-one-color-profile.png");
211 EXPECT_EQ(1u, decodedFramesCount());
212 EXPECT_EQ(65536u, decodedSize());
213 EXPECT_TRUE(m_image
->hasColorProfile());
216 TEST_F(BitmapImageTest
, webpHasColorProfile
)
218 loadImage("/LayoutTests/fast/images/resources/webp-color-profile-lossy.webp");
219 EXPECT_EQ(1u, decodedFramesCount());
220 EXPECT_EQ(2560000u, decodedSize());
221 EXPECT_TRUE(m_image
->hasColorProfile());
224 #endif // USE(QCMSLIB)
226 TEST_F(BitmapImageTest
, icoHasWrongFrameDimensions
)
228 loadImage("/LayoutTests/fast/images/resources/wrong-frame-dimensions.ico");
229 // This call would cause crash without fix for 408026
230 imageForDefaultFrame();
233 TEST_F(BitmapImageTest
, correctDecodedDataSize
)
235 // When requesting a frame of a multi-frame GIF causes another frame to be
236 // decoded as well, both frames' sizes should be included in the decoded
237 // size changed notification.
238 loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false);
240 int frameSize
= static_cast<int>(m_image
->size().area() * sizeof(ImageFrame::PixelData
));
241 EXPECT_EQ(frameSize
* 2, m_imageObserver
.m_lastDecodedSizeChangedDelta
);
243 // Trying to destroy all data except an undecoded frame should cause the
244 // decoder to seek backwards and preserve the most recent previous frame
245 // necessary to decode that undecoded frame, and destroy all other frames.
247 destroyDecodedData(false);
248 EXPECT_EQ(-frameSize
, m_imageObserver
.m_lastDecodedSizeChangedDelta
);
251 class BitmapImageDeferredDecodingTest
: public BitmapImageTest
{
253 BitmapImageDeferredDecodingTest() : BitmapImageTest(true) { }
256 TEST_F(BitmapImageDeferredDecodingTest
, correctDecodedDataSize
)
258 // When deferred decoding is enabled, requesting any one frame shouldn't
259 // result in decoding any other frames.
260 loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false);
262 int frameSize
= static_cast<int>(m_image
->size().area() * sizeof(ImageFrame::PixelData
));
263 EXPECT_EQ(frameSize
, m_imageObserver
.m_lastDecodedSizeChangedDelta
);
266 // Trying to destroy all data except an undecoded frame should go ahead and
267 // destroy all other frames.
269 destroyDecodedData(false);
270 EXPECT_EQ(-frameSize
* 2, m_imageObserver
.m_lastDecodedSizeChangedDelta
);