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/ImageFrameGenerator.h"
29 #include "platform/SharedBuffer.h"
30 #include "platform/Task.h"
31 #include "platform/ThreadSafeFunctional.h"
32 #include "platform/graphics/ImageDecodingStore.h"
33 #include "platform/graphics/test/MockImageDecoder.h"
34 #include "public/platform/Platform.h"
35 #include "public/platform/WebThread.h"
36 #include "public/platform/WebTraceLocation.h"
37 #include <gtest/gtest.h>
43 // Helper methods to generate standard sizes.
44 SkISize
fullSize() { return SkISize::Make(100, 100); }
46 SkImageInfo
imageInfo()
48 return SkImageInfo::Make(100, 100, kBGRA_8888_SkColorType
, kOpaque_SkAlphaType
);
53 class ImageFrameGeneratorTest
: public ::testing::Test
, public MockImageDecoderClient
{
57 ImageDecodingStore::instance().setCacheLimitInBytes(1024 * 1024);
58 m_data
= SharedBuffer::create();
59 m_generator
= ImageFrameGenerator::create(fullSize(), m_data
, false);
60 useMockImageDecoderFactory();
61 m_decodersDestroyed
= 0;
62 m_decodeRequestCount
= 0;
63 m_status
= ImageFrame::FrameEmpty
;
67 void TearDown() override
69 ImageDecodingStore::instance().clear();
72 void decoderBeingDestroyed() override
74 ++m_decodersDestroyed
;
77 void decodeRequested() override
79 ++m_decodeRequestCount
;
82 ImageFrame::Status
status() override
84 ImageFrame::Status currentStatus
= m_status
;
85 m_status
= m_nextFrameStatus
;
89 size_t frameCount() override
{ return m_frameCount
; }
90 int repetitionCount() const override
{ return m_frameCount
== 1 ? cAnimationNone
:cAnimationLoopOnce
; }
91 float frameDuration() const override
{ return 0; }
94 void useMockImageDecoderFactory()
96 m_generator
->setImageDecoderFactory(MockImageDecoderFactory::create(this, fullSize()));
101 m_data
->append("g", 1);
102 m_generator
->setData(m_data
, false);
105 void setFrameStatus(ImageFrame::Status status
) { m_status
= m_nextFrameStatus
= status
; }
106 void setNextFrameStatus(ImageFrame::Status status
) { m_nextFrameStatus
= status
; }
107 void setFrameCount(size_t count
)
109 m_frameCount
= count
;
112 m_generator
= ImageFrameGenerator::create(fullSize(), m_data
, true, true);
113 useMockImageDecoderFactory();
117 RefPtr
<SharedBuffer
> m_data
;
118 RefPtr
<ImageFrameGenerator
> m_generator
;
119 int m_decodersDestroyed
;
120 int m_decodeRequestCount
;
121 ImageFrame::Status m_status
;
122 ImageFrame::Status m_nextFrameStatus
;
126 TEST_F(ImageFrameGeneratorTest
, incompleteDecode
)
128 setFrameStatus(ImageFrame::FramePartial
);
130 char buffer
[100 * 100 * 4];
131 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
132 EXPECT_EQ(1, m_decodeRequestCount
);
135 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
136 EXPECT_EQ(2, m_decodeRequestCount
);
137 EXPECT_EQ(0, m_decodersDestroyed
);
140 TEST_F(ImageFrameGeneratorTest
, incompleteDecodeBecomesComplete
)
142 setFrameStatus(ImageFrame::FramePartial
);
144 char buffer
[100 * 100 * 4];
145 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
146 EXPECT_EQ(1, m_decodeRequestCount
);
147 EXPECT_EQ(0, m_decodersDestroyed
);
149 setFrameStatus(ImageFrame::FrameComplete
);
152 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
153 EXPECT_EQ(2, m_decodeRequestCount
);
154 EXPECT_EQ(1, m_decodersDestroyed
);
156 // Decoder created again.
157 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
158 EXPECT_EQ(3, m_decodeRequestCount
);
161 static void decodeThreadMain(ImageFrameGenerator
* generator
)
163 char buffer
[100 * 100 * 4];
164 generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
167 TEST_F(ImageFrameGeneratorTest
, incompleteDecodeBecomesCompleteMultiThreaded
)
169 setFrameStatus(ImageFrame::FramePartial
);
171 char buffer
[100 * 100 * 4];
172 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
173 EXPECT_EQ(1, m_decodeRequestCount
);
174 EXPECT_EQ(0, m_decodersDestroyed
);
176 // LocalFrame can now be decoded completely.
177 setFrameStatus(ImageFrame::FrameComplete
);
179 OwnPtr
<WebThread
> thread
= adoptPtr(Platform::current()->createThread("DecodeThread"));
180 thread
->taskRunner()->postTask(FROM_HERE
, new Task(threadSafeBind(&decodeThreadMain
, AllowCrossThreadAccess(m_generator
.get()))));
182 EXPECT_EQ(2, m_decodeRequestCount
);
183 EXPECT_EQ(1, m_decodersDestroyed
);
185 // Decoder created again.
186 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
187 EXPECT_EQ(3, m_decodeRequestCount
);
190 TEST_F(ImageFrameGeneratorTest
, frameHasAlpha
)
192 setFrameStatus(ImageFrame::FramePartial
);
194 char buffer
[100 * 100 * 4];
195 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
196 EXPECT_TRUE(m_generator
->hasAlpha(0));
197 EXPECT_EQ(1, m_decodeRequestCount
);
199 ImageDecoder
* tempDecoder
= 0;
200 EXPECT_TRUE(ImageDecodingStore::instance().lockDecoder(m_generator
.get(), fullSize(), &tempDecoder
));
201 ASSERT_TRUE(tempDecoder
);
202 tempDecoder
->frameBufferAtIndex(0)->setHasAlpha(false);
203 ImageDecodingStore::instance().unlockDecoder(m_generator
.get(), tempDecoder
);
204 EXPECT_EQ(2, m_decodeRequestCount
);
206 setFrameStatus(ImageFrame::FrameComplete
);
207 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
208 EXPECT_EQ(3, m_decodeRequestCount
);
209 EXPECT_FALSE(m_generator
->hasAlpha(0));
212 TEST_F(ImageFrameGeneratorTest
, removeMultiFrameDecoder
)
215 setFrameStatus(ImageFrame::FrameComplete
);
217 char buffer
[100 * 100 * 4];
218 m_generator
->decodeAndScale(imageInfo(), 0, buffer
, 100 * 4);
219 EXPECT_EQ(1, m_decodeRequestCount
);
220 EXPECT_EQ(0, m_decodersDestroyed
);
222 setFrameStatus(ImageFrame::FrameComplete
);
224 m_generator
->decodeAndScale(imageInfo(), 1, buffer
, 100 * 4);
225 EXPECT_EQ(2, m_decodeRequestCount
);
226 EXPECT_EQ(0, m_decodersDestroyed
);
228 setFrameStatus(ImageFrame::FrameComplete
);
230 // Multi frame decoder should be removed.
231 m_generator
->decodeAndScale(imageInfo(), 2, buffer
, 100 * 4);
232 EXPECT_EQ(3, m_decodeRequestCount
);
233 EXPECT_EQ(1, m_decodersDestroyed
);