2 * Copyright (C) 2012 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
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "platform/graphics/DeferredImageDecoder.h"
29 #include "SkBitmapDevice.h"
31 #include "SkPicture.h"
32 #include "SkPictureRecorder.h"
33 #include "SkSurface.h"
34 #include "platform/SharedBuffer.h"
35 #include "platform/Task.h"
36 #include "platform/ThreadSafeFunctional.h"
37 #include "platform/graphics/ImageDecodingStore.h"
38 #include "platform/graphics/test/MockImageDecoder.h"
39 #include "public/platform/Platform.h"
40 #include "public/platform/WebThread.h"
41 #include "public/platform/WebTraceLocation.h"
42 #include "third_party/skia/include/core/SkImage.h"
43 #include "third_party/skia/include/core/SkPixmap.h"
44 #include "wtf/PassRefPtr.h"
45 #include "wtf/RefPtr.h"
46 #include <gtest/gtest.h>
52 // Raw data for a PNG file with 1x1 white pixels.
53 const unsigned char whitePNG
[] = {
54 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00,
55 0x00, 0x0d, 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01,
56 0x00, 0x00, 0x00, 0x01, 0x08, 0x02, 0x00, 0x00, 0x00, 0x90,
57 0x77, 0x53, 0xde, 0x00, 0x00, 0x00, 0x01, 0x73, 0x52, 0x47,
58 0x42, 0x00, 0xae, 0xce, 0x1c, 0xe9, 0x00, 0x00, 0x00, 0x09,
59 0x70, 0x48, 0x59, 0x73, 0x00, 0x00, 0x0b, 0x13, 0x00, 0x00,
60 0x0b, 0x13, 0x01, 0x00, 0x9a, 0x9c, 0x18, 0x00, 0x00, 0x00,
61 0x0c, 0x49, 0x44, 0x41, 0x54, 0x08, 0xd7, 0x63, 0xf8, 0xff,
62 0xff, 0x3f, 0x00, 0x05, 0xfe, 0x02, 0xfe, 0xdc, 0xcc, 0x59,
63 0xe7, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4e, 0x44, 0xae,
74 class DeferredImageDecoderTest
: public ::testing::Test
, public MockImageDecoderClient
{
78 ImageDecodingStore::instance().setCacheLimitInBytes(1024 * 1024);
79 DeferredImageDecoder::setEnabled(true);
80 m_data
= SharedBuffer::create(whitePNG
, sizeof(whitePNG
));
82 OwnPtr
<MockImageDecoder
> decoder
= MockImageDecoder::create(this);
83 m_actualDecoder
= decoder
.get();
84 m_actualDecoder
->setSize(1, 1);
85 m_lazyDecoder
= DeferredImageDecoder::createForTesting(decoder
.release());
86 m_surface
.reset(SkSurface::NewRasterN32Premul(100, 100));
87 ASSERT_TRUE(m_surface
.get());
88 m_decodeRequestCount
= 0;
89 m_repetitionCount
= cAnimationNone
;
90 m_status
= ImageFrame::FrameComplete
;
92 m_decodedSize
= m_actualDecoder
->size();
95 void TearDown() override
97 ImageDecodingStore::instance().clear();
100 void decoderBeingDestroyed() override
105 void decodeRequested() override
107 ++m_decodeRequestCount
;
110 size_t frameCount() override
115 int repetitionCount() const override
117 return m_repetitionCount
;
120 ImageFrame::Status
status() override
125 float frameDuration() const override
127 return m_frameDuration
;
130 IntSize
decodedSize() const override
132 return m_decodedSize
;
136 void useMockImageDecoderFactory()
138 m_lazyDecoder
->frameGenerator()->setImageDecoderFactory(MockImageDecoderFactory::create(this, m_decodedSize
));
141 // Don't own this but saves the pointer to query states.
142 MockImageDecoder
* m_actualDecoder
;
143 OwnPtr
<DeferredImageDecoder
> m_lazyDecoder
;
144 SkAutoTUnref
<SkSurface
> m_surface
;
145 int m_decodeRequestCount
;
146 RefPtr
<SharedBuffer
> m_data
;
148 int m_repetitionCount
;
149 ImageFrame::Status m_status
;
150 float m_frameDuration
;
151 IntSize m_decodedSize
;
154 TEST_F(DeferredImageDecoderTest
, drawIntoSkPicture
)
156 m_lazyDecoder
->setData(*m_data
, true);
157 RefPtr
<SkImage
> image
= m_lazyDecoder
->createFrameAtIndex(0);
159 EXPECT_EQ(1, image
->width());
160 EXPECT_EQ(1, image
->height());
162 SkPictureRecorder recorder
;
163 SkCanvas
* tempCanvas
= recorder
.beginRecording(100, 100, 0, 0);
164 tempCanvas
->drawImage(image
.get(), 0, 0);
165 RefPtr
<SkPicture
> picture
= adoptRef(recorder
.endRecording());
166 EXPECT_EQ(0, m_decodeRequestCount
);
168 m_surface
->getCanvas()->drawPicture(picture
.get());
169 EXPECT_EQ(0, m_decodeRequestCount
);
171 SkBitmap canvasBitmap
;
172 canvasBitmap
.allocN32Pixels(100, 100);
173 ASSERT_TRUE(m_surface
->getCanvas()->readPixels(&canvasBitmap
, 0, 0));
174 SkAutoLockPixels
autoLock(canvasBitmap
);
175 EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap
.getColor(0, 0));
178 TEST_F(DeferredImageDecoderTest
, drawIntoSkPictureProgressive
)
180 RefPtr
<SharedBuffer
> partialData
= SharedBuffer::create(m_data
->data(), m_data
->size() - 10);
182 // Received only half the file.
183 m_lazyDecoder
->setData(*partialData
, false);
184 RefPtr
<SkImage
> image
= m_lazyDecoder
->createFrameAtIndex(0);
186 SkPictureRecorder recorder
;
187 SkCanvas
* tempCanvas
= recorder
.beginRecording(100, 100, 0, 0);
188 tempCanvas
->drawImage(image
.get(), 0, 0);
189 RefPtr
<SkPicture
> picture
= adoptRef(recorder
.endRecording());
190 m_surface
->getCanvas()->drawPicture(picture
.get());
192 // Fully received the file and draw the SkPicture again.
193 m_lazyDecoder
->setData(*m_data
, true);
194 image
= m_lazyDecoder
->createFrameAtIndex(0);
196 tempCanvas
= recorder
.beginRecording(100, 100, 0, 0);
197 tempCanvas
->drawImage(image
.get(), 0, 0);
198 picture
= adoptRef(recorder
.endRecording());
199 m_surface
->getCanvas()->drawPicture(picture
.get());
201 SkBitmap canvasBitmap
;
202 canvasBitmap
.allocN32Pixels(100, 100);
203 ASSERT_TRUE(m_surface
->getCanvas()->readPixels(&canvasBitmap
, 0, 0));
204 SkAutoLockPixels
autoLock(canvasBitmap
);
205 EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap
.getColor(0, 0));
208 static void rasterizeMain(SkCanvas
* canvas
, SkPicture
* picture
)
210 canvas
->drawPicture(picture
);
213 TEST_F(DeferredImageDecoderTest
, decodeOnOtherThread
)
215 m_lazyDecoder
->setData(*m_data
, true);
216 RefPtr
<SkImage
> image
= m_lazyDecoder
->createFrameAtIndex(0);
218 EXPECT_EQ(1, image
->width());
219 EXPECT_EQ(1, image
->height());
221 SkPictureRecorder recorder
;
222 SkCanvas
* tempCanvas
= recorder
.beginRecording(100, 100, 0, 0);
223 tempCanvas
->drawImage(image
.get(), 0, 0);
224 RefPtr
<SkPicture
> picture
= adoptRef(recorder
.endRecording());
225 EXPECT_EQ(0, m_decodeRequestCount
);
227 // Create a thread to rasterize SkPicture.
228 OwnPtr
<WebThread
> thread
= adoptPtr(Platform::current()->createThread("RasterThread"));
229 thread
->taskRunner()->postTask(FROM_HERE
, new Task(threadSafeBind(&rasterizeMain
, AllowCrossThreadAccess(m_surface
->getCanvas()), AllowCrossThreadAccess(picture
.get()))));
231 EXPECT_EQ(0, m_decodeRequestCount
);
233 SkBitmap canvasBitmap
;
234 canvasBitmap
.allocN32Pixels(100, 100);
235 ASSERT_TRUE(m_surface
->getCanvas()->readPixels(&canvasBitmap
, 0, 0));
236 SkAutoLockPixels
autoLock(canvasBitmap
);
237 EXPECT_EQ(SkColorSetARGB(255, 255, 255, 255), canvasBitmap
.getColor(0, 0));
240 TEST_F(DeferredImageDecoderTest
, singleFrameImageLoading
)
242 m_status
= ImageFrame::FramePartial
;
243 m_lazyDecoder
->setData(*m_data
, false);
244 EXPECT_FALSE(m_lazyDecoder
->frameIsCompleteAtIndex(0));
245 RefPtr
<SkImage
> image
= m_lazyDecoder
->createFrameAtIndex(0);
247 unsigned firstId
= image
->uniqueID();
248 EXPECT_FALSE(m_lazyDecoder
->frameIsCompleteAtIndex(0));
249 EXPECT_TRUE(m_actualDecoder
);
251 m_status
= ImageFrame::FrameComplete
;
252 m_data
->append(" ", 1);
253 m_lazyDecoder
->setData(*m_data
, true);
254 EXPECT_FALSE(m_actualDecoder
);
255 EXPECT_TRUE(m_lazyDecoder
->frameIsCompleteAtIndex(0));
257 image
= m_lazyDecoder
->createFrameAtIndex(0);
259 unsigned secondId
= image
->uniqueID();
260 EXPECT_FALSE(m_decodeRequestCount
);
261 EXPECT_NE(firstId
, secondId
);
264 TEST_F(DeferredImageDecoderTest
, multiFrameImageLoading
)
266 m_repetitionCount
= 10;
268 m_frameDuration
= 10;
269 m_status
= ImageFrame::FramePartial
;
270 m_lazyDecoder
->setData(*m_data
, false);
272 RefPtr
<SkImage
> image
= m_lazyDecoder
->createFrameAtIndex(0);
274 unsigned firstId
= image
->uniqueID();
275 EXPECT_FALSE(m_lazyDecoder
->frameIsCompleteAtIndex(0));
276 EXPECT_EQ(10.0f
, m_lazyDecoder
->frameDurationAtIndex(0));
279 m_frameDuration
= 20;
280 m_status
= ImageFrame::FrameComplete
;
281 m_data
->append(" ", 1);
282 m_lazyDecoder
->setData(*m_data
, false);
284 image
= m_lazyDecoder
->createFrameAtIndex(0);
286 unsigned secondId
= image
->uniqueID();
287 EXPECT_NE(firstId
, secondId
);
288 EXPECT_TRUE(m_lazyDecoder
->frameIsCompleteAtIndex(0));
289 EXPECT_TRUE(m_lazyDecoder
->frameIsCompleteAtIndex(1));
290 EXPECT_EQ(20.0f
, m_lazyDecoder
->frameDurationAtIndex(1));
291 EXPECT_TRUE(m_actualDecoder
);
294 m_frameDuration
= 30;
295 m_status
= ImageFrame::FrameComplete
;
296 m_lazyDecoder
->setData(*m_data
, true);
297 EXPECT_FALSE(m_actualDecoder
);
298 EXPECT_TRUE(m_lazyDecoder
->frameIsCompleteAtIndex(0));
299 EXPECT_TRUE(m_lazyDecoder
->frameIsCompleteAtIndex(1));
300 EXPECT_TRUE(m_lazyDecoder
->frameIsCompleteAtIndex(2));
301 EXPECT_EQ(10.0f
, m_lazyDecoder
->frameDurationAtIndex(0));
302 EXPECT_EQ(20.0f
, m_lazyDecoder
->frameDurationAtIndex(1));
303 EXPECT_EQ(30.0f
, m_lazyDecoder
->frameDurationAtIndex(2));
304 EXPECT_EQ(10, m_lazyDecoder
->repetitionCount());
307 TEST_F(DeferredImageDecoderTest
, decodedSize
)
309 m_decodedSize
= IntSize(22, 33);
310 m_lazyDecoder
->setData(*m_data
, true);
311 RefPtr
<SkImage
> image
= m_lazyDecoder
->createFrameAtIndex(0);
313 EXPECT_EQ(m_decodedSize
.width(), image
->width());
314 EXPECT_EQ(m_decodedSize
.height(), image
->height());
316 useMockImageDecoderFactory();
318 // The following code should not fail any assert.
319 SkPictureRecorder recorder
;
320 SkCanvas
* tempCanvas
= recorder
.beginRecording(100, 100, 0, 0);
321 tempCanvas
->drawImage(image
.get(), 0, 0);
322 RefPtr
<SkPicture
> picture
= adoptRef(recorder
.endRecording());
323 EXPECT_EQ(0, m_decodeRequestCount
);
324 m_surface
->getCanvas()->drawPicture(picture
.get());
325 EXPECT_EQ(1, m_decodeRequestCount
);
328 TEST_F(DeferredImageDecoderTest
, smallerFrameCount
)
331 m_lazyDecoder
->setData(*m_data
, false);
332 EXPECT_EQ(m_frameCount
, m_lazyDecoder
->frameCount());
334 m_lazyDecoder
->setData(*m_data
, false);
335 EXPECT_EQ(m_frameCount
, m_lazyDecoder
->frameCount());
337 m_lazyDecoder
->setData(*m_data
, true);
338 EXPECT_EQ(m_frameCount
, m_lazyDecoder
->frameCount());
341 TEST_F(DeferredImageDecoderTest
, frameOpacity
)
343 OwnPtr
<ImageDecoder
> actualDecoder
= ImageDecoder::create(*m_data
,
344 ImageDecoder::AlphaPremultiplied
, ImageDecoder::GammaAndColorProfileApplied
);
345 OwnPtr
<DeferredImageDecoder
> decoder
= DeferredImageDecoder::createForTesting(actualDecoder
.release());
346 decoder
->setData(*m_data
, true);
348 SkImageInfo pixInfo
= SkImageInfo::MakeN32Premul(1, 1);
349 SkAutoPixmapStorage pixels
;
350 pixels
.alloc(pixInfo
);
352 // Before decoding, the frame is not known to be opaque.
353 RefPtr
<SkImage
> frame
= decoder
->createFrameAtIndex(0);
355 EXPECT_FALSE(frame
->isOpaque());
357 // Force a lazy decode by reading pixels.
358 EXPECT_TRUE(frame
->readPixels(pixels
, 0, 0));
360 // After decoding, the frame is known to be opaque.
361 frame
= decoder
->createFrameAtIndex(0);
363 EXPECT_TRUE(frame
->isOpaque());
365 // Re-generating the opaque-marked frame should not fail.
366 EXPECT_TRUE(frame
->readPixels(pixels
, 0, 0));