| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2012 Google Inc. All rights reserved. |
| 3 * | 3 * |
| 4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
| 5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
| 6 * are met: | 6 * are met: |
| 7 * | 7 * |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 11 matching lines...) Expand all Loading... |
| 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 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. | 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 24 */ | 24 */ |
| 25 | 25 |
| 26 #include "platform/graphics/ImageFrameGenerator.h" | 26 #include "platform/graphics/ImageFrameGenerator.h" |
| 27 | 27 |
| 28 #include "platform/SharedBuffer.h" | 28 #include "platform/SharedBuffer.h" |
| 29 #include "platform/ThreadSafeFunctional.h" | 29 #include "platform/ThreadSafeFunctional.h" |
| 30 #include "platform/graphics/ImageDecodingStore.h" | 30 #include "platform/graphics/ImageDecodingStore.h" |
| 31 #include "platform/graphics/test/MockImageDecoder.h" | 31 #include "platform/graphics/test/MockImageDecoder.h" |
| 32 #include "platform/image-decoders/SegmentReader.h" | |
| 33 #include "public/platform/Platform.h" | 32 #include "public/platform/Platform.h" |
| 34 #include "public/platform/WebTaskRunner.h" | 33 #include "public/platform/WebTaskRunner.h" |
| 35 #include "public/platform/WebThread.h" | 34 #include "public/platform/WebThread.h" |
| 36 #include "public/platform/WebTraceLocation.h" | 35 #include "public/platform/WebTraceLocation.h" |
| 37 #include "testing/gtest/include/gtest/gtest.h" | 36 #include "testing/gtest/include/gtest/gtest.h" |
| 38 | 37 |
| 39 namespace blink { | 38 namespace blink { |
| 40 | 39 |
| 41 namespace { | 40 namespace { |
| 42 | 41 |
| 43 // Helper methods to generate standard sizes. | 42 // Helper methods to generate standard sizes. |
| 44 SkISize fullSize() { return SkISize::Make(100, 100); } | 43 SkISize fullSize() { return SkISize::Make(100, 100); } |
| 45 | 44 |
| 46 SkImageInfo imageInfo() | 45 SkImageInfo imageInfo() |
| 47 { | 46 { |
| 48 return SkImageInfo::Make(100, 100, kBGRA_8888_SkColorType, kOpaque_SkAlphaTy
pe); | 47 return SkImageInfo::Make(100, 100, kBGRA_8888_SkColorType, kOpaque_SkAlphaTy
pe); |
| 49 } | 48 } |
| 50 | 49 |
| 51 } // namespace | 50 } // namespace |
| 52 | 51 |
| 53 class ImageFrameGeneratorTest : public ::testing::Test, public MockImageDecoderC
lient { | 52 class ImageFrameGeneratorTest : public ::testing::Test, public MockImageDecoderC
lient { |
| 54 public: | 53 public: |
| 55 void SetUp() override | 54 void SetUp() override |
| 56 { | 55 { |
| 57 ImageDecodingStore::instance().setCacheLimitInBytes(1024 * 1024); | 56 ImageDecodingStore::instance().setCacheLimitInBytes(1024 * 1024); |
| 58 m_generator = ImageFrameGenerator::create(fullSize(), false); | |
| 59 m_data = SharedBuffer::create(); | 57 m_data = SharedBuffer::create(); |
| 60 m_segmentReader = SegmentReader::createFromSharedBuffer(m_data); | 58 m_generator = ImageFrameGenerator::create(fullSize(), m_data, false); |
| 61 useMockImageDecoderFactory(); | 59 useMockImageDecoderFactory(); |
| 62 m_decodersDestroyed = 0; | 60 m_decodersDestroyed = 0; |
| 63 m_decodeRequestCount = 0; | 61 m_decodeRequestCount = 0; |
| 64 m_status = ImageFrame::FrameEmpty; | 62 m_status = ImageFrame::FrameEmpty; |
| 65 m_frameCount = 1; | 63 m_frameCount = 1; |
| 66 m_requestedClearExceptFrame = kNotFound; | 64 m_requestedClearExceptFrame = kNotFound; |
| 67 } | 65 } |
| 68 | 66 |
| 69 void TearDown() override | 67 void TearDown() override |
| 70 { | 68 { |
| (...skipping 25 matching lines...) Expand all Loading... |
| 96 size_t frameCount() override { return m_frameCount; } | 94 size_t frameCount() override { return m_frameCount; } |
| 97 int repetitionCount() const override { return m_frameCount == 1 ? cAnimation
None:cAnimationLoopOnce; } | 95 int repetitionCount() const override { return m_frameCount == 1 ? cAnimation
None:cAnimationLoopOnce; } |
| 98 float frameDuration() const override { return 0; } | 96 float frameDuration() const override { return 0; } |
| 99 | 97 |
| 100 protected: | 98 protected: |
| 101 void useMockImageDecoderFactory() | 99 void useMockImageDecoderFactory() |
| 102 { | 100 { |
| 103 m_generator->setImageDecoderFactory(MockImageDecoderFactory::create(this
, fullSize())); | 101 m_generator->setImageDecoderFactory(MockImageDecoderFactory::create(this
, fullSize())); |
| 104 } | 102 } |
| 105 | 103 |
| 106 void addNewData() | 104 void addNewData(bool allDataReceived = false) |
| 107 { | 105 { |
| 108 m_data->append("g", 1u); | 106 m_data->append("g", 1u); |
| 107 m_generator->setData(m_data, allDataReceived); |
| 109 } | 108 } |
| 110 | 109 |
| 111 void setFrameStatus(ImageFrame::Status status) { m_status = m_nextFrameStat
us = status; } | 110 void setFrameStatus(ImageFrame::Status status) { m_status = m_nextFrameStat
us = status; } |
| 112 void setNextFrameStatus(ImageFrame::Status status) { m_nextFrameStatus = st
atus; } | 111 void setNextFrameStatus(ImageFrame::Status status) { m_nextFrameStatus = st
atus; } |
| 113 void setFrameCount(size_t count) | 112 void setFrameCount(size_t count) |
| 114 { | 113 { |
| 115 m_frameCount = count; | 114 m_frameCount = count; |
| 116 if (count > 1) { | 115 if (count > 1) { |
| 117 m_generator.clear(); | 116 m_generator.clear(); |
| 118 m_generator = ImageFrameGenerator::create(fullSize(), true); | 117 m_generator = ImageFrameGenerator::create(fullSize(), m_data, true,
true); |
| 119 useMockImageDecoderFactory(); | 118 useMockImageDecoderFactory(); |
| 120 } | 119 } |
| 121 } | 120 } |
| 122 | 121 |
| 123 RefPtr<SharedBuffer> m_data; | 122 RefPtr<SharedBuffer> m_data; |
| 124 RefPtr<SegmentReader> m_segmentReader; | |
| 125 RefPtr<ImageFrameGenerator> m_generator; | 123 RefPtr<ImageFrameGenerator> m_generator; |
| 126 int m_decodersDestroyed; | 124 int m_decodersDestroyed; |
| 127 int m_decodeRequestCount; | 125 int m_decodeRequestCount; |
| 128 ImageFrame::Status m_status; | 126 ImageFrame::Status m_status; |
| 129 ImageFrame::Status m_nextFrameStatus; | 127 ImageFrame::Status m_nextFrameStatus; |
| 130 size_t m_frameCount; | 128 size_t m_frameCount; |
| 131 size_t m_requestedClearExceptFrame; | 129 size_t m_requestedClearExceptFrame; |
| 132 }; | 130 }; |
| 133 | 131 |
| 134 TEST_F(ImageFrameGeneratorTest, incompleteDecode) | 132 TEST_F(ImageFrameGeneratorTest, incompleteDecode) |
| 135 { | 133 { |
| 136 setFrameStatus(ImageFrame::FramePartial); | 134 setFrameStatus(ImageFrame::FramePartial); |
| 137 | 135 |
| 138 char buffer[100 * 100 * 4]; | 136 char buffer[100 * 100 * 4]; |
| 139 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 137 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 140 EXPECT_EQ(1, m_decodeRequestCount); | 138 EXPECT_EQ(1, m_decodeRequestCount); |
| 141 | 139 |
| 142 addNewData(); | 140 addNewData(); |
| 143 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 141 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 144 EXPECT_EQ(2, m_decodeRequestCount); | 142 EXPECT_EQ(2, m_decodeRequestCount); |
| 145 EXPECT_EQ(0, m_decodersDestroyed); | 143 EXPECT_EQ(0, m_decodersDestroyed); |
| 146 } | 144 } |
| 147 | 145 |
| 148 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesComplete) | 146 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesComplete) |
| 149 { | 147 { |
| 150 setFrameStatus(ImageFrame::FramePartial); | 148 setFrameStatus(ImageFrame::FramePartial); |
| 151 | 149 |
| 152 char buffer[100 * 100 * 4]; | 150 char buffer[100 * 100 * 4]; |
| 153 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 151 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 154 EXPECT_EQ(1, m_decodeRequestCount); | 152 EXPECT_EQ(1, m_decodeRequestCount); |
| 155 EXPECT_EQ(0, m_decodersDestroyed); | 153 EXPECT_EQ(0, m_decodersDestroyed); |
| 156 | 154 |
| 157 setFrameStatus(ImageFrame::FrameComplete); | 155 setFrameStatus(ImageFrame::FrameComplete); |
| 158 addNewData(); | 156 addNewData(); |
| 159 | 157 |
| 160 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 158 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 161 EXPECT_EQ(2, m_decodeRequestCount); | 159 EXPECT_EQ(2, m_decodeRequestCount); |
| 162 EXPECT_EQ(1, m_decodersDestroyed); | 160 EXPECT_EQ(1, m_decodersDestroyed); |
| 163 | 161 |
| 164 // Decoder created again. | 162 // Decoder created again. |
| 165 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 163 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 166 EXPECT_EQ(3, m_decodeRequestCount); | 164 EXPECT_EQ(3, m_decodeRequestCount); |
| 167 } | 165 } |
| 168 | 166 |
| 169 static void decodeThreadMain(ImageFrameGenerator* generator, SegmentReader* segm
entReader) | 167 static void decodeThreadMain(ImageFrameGenerator* generator) |
| 170 { | 168 { |
| 171 char buffer[100 * 100 * 4]; | 169 char buffer[100 * 100 * 4]; |
| 172 generator->decodeAndScale(segmentReader, false, 0, imageInfo(), buffer, 100
* 4); | 170 generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 171 } |
| 172 |
| 173 static void decodeThreadWithRefEncodedMain(ImageFrameGenerator* generator) |
| 174 { |
| 175 // Image must be complete - refEncodedData otherwise returns null. |
| 176 char buffer[100 * 100 * 4]; |
| 177 SkData* data = generator->refEncodedData(); |
| 178 generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 179 data->unref(); |
| 173 } | 180 } |
| 174 | 181 |
| 175 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesCompleteMultiThreaded) | 182 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesCompleteMultiThreaded) |
| 176 { | 183 { |
| 177 setFrameStatus(ImageFrame::FramePartial); | 184 setFrameStatus(ImageFrame::FramePartial); |
| 178 | 185 |
| 179 char buffer[100 * 100 * 4]; | 186 char buffer[100 * 100 * 4]; |
| 180 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 187 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 181 EXPECT_EQ(1, m_decodeRequestCount); | 188 EXPECT_EQ(1, m_decodeRequestCount); |
| 182 EXPECT_EQ(0, m_decodersDestroyed); | 189 EXPECT_EQ(0, m_decodersDestroyed); |
| 190 SkData* data = m_generator->refEncodedData(); |
| 191 EXPECT_EQ(nullptr, data); |
| 183 | 192 |
| 184 // LocalFrame can now be decoded completely. | 193 // LocalFrame can now be decoded completely. |
| 185 setFrameStatus(ImageFrame::FrameComplete); | 194 setFrameStatus(ImageFrame::FrameComplete); |
| 186 addNewData(); | 195 addNewData(); |
| 196 // addNewData is calling m_generator->setData with allDataReceived == false,
which means that |
| 197 // refEncodedData should return null. |
| 198 data = m_generator->refEncodedData(); |
| 199 EXPECT_EQ(nullptr, data); |
| 187 OwnPtr<WebThread> thread = adoptPtr(Platform::current()->createThread("Decod
eThread")); | 200 OwnPtr<WebThread> thread = adoptPtr(Platform::current()->createThread("Decod
eThread")); |
| 188 thread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&decode
ThreadMain, AllowCrossThreadAccess(m_generator.get()), AllowCrossThreadAccess(m_
segmentReader.get()))); | 201 thread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&decode
ThreadMain, AllowCrossThreadAccess(m_generator.get()))); |
| 189 thread.clear(); | 202 thread.clear(); |
| 190 EXPECT_EQ(2, m_decodeRequestCount); | 203 EXPECT_EQ(2, m_decodeRequestCount); |
| 191 EXPECT_EQ(1, m_decodersDestroyed); | 204 EXPECT_EQ(1, m_decodersDestroyed); |
| 192 | 205 |
| 193 // Decoder created again. | 206 // Decoder created again. |
| 194 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 207 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 195 EXPECT_EQ(3, m_decodeRequestCount); | 208 EXPECT_EQ(3, m_decodeRequestCount); |
| 196 | 209 |
| 197 addNewData(); | 210 addNewData(true); |
| 211 data = m_generator->refEncodedData(); |
| 212 ASSERT_TRUE(data); |
| 213 // To prevent data writting, SkData::unique() should be false. |
| 214 ASSERT_TRUE(!data->unique()); |
| 198 | 215 |
| 199 // Delete generator. | 216 // Thread will also ref and unref the data. |
| 217 thread = adoptPtr(Platform::current()->createThread("RefEncodedDataThread"))
; |
| 218 thread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, threadSafeBind(&decode
ThreadWithRefEncodedMain, AllowCrossThreadAccess(m_generator.get()))); |
| 219 thread.clear(); |
| 220 EXPECT_EQ(4, m_decodeRequestCount); |
| 221 |
| 222 data->unref(); |
| 223 // m_generator is holding the only reference to SkData now. |
| 224 ASSERT_TRUE(data->unique()); |
| 225 |
| 226 data = m_generator->refEncodedData(); |
| 227 ASSERT_TRUE(data && !data->unique()); |
| 228 |
| 229 // Delete generator, and SkData should have the only reference. |
| 200 m_generator = nullptr; | 230 m_generator = nullptr; |
| 231 ASSERT_TRUE(data->unique()); |
| 232 data->unref(); |
| 201 } | 233 } |
| 202 | 234 |
| 203 TEST_F(ImageFrameGeneratorTest, frameHasAlpha) | 235 TEST_F(ImageFrameGeneratorTest, frameHasAlpha) |
| 204 { | 236 { |
| 205 setFrameStatus(ImageFrame::FramePartial); | 237 setFrameStatus(ImageFrame::FramePartial); |
| 206 | 238 |
| 207 char buffer[100 * 100 * 4]; | 239 char buffer[100 * 100 * 4]; |
| 208 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 240 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 209 EXPECT_TRUE(m_generator->hasAlpha(0)); | 241 EXPECT_TRUE(m_generator->hasAlpha(0)); |
| 210 EXPECT_EQ(1, m_decodeRequestCount); | 242 EXPECT_EQ(1, m_decodeRequestCount); |
| 211 | 243 |
| 212 ImageDecoder* tempDecoder = 0; | 244 ImageDecoder* tempDecoder = 0; |
| 213 EXPECT_TRUE(ImageDecodingStore::instance().lockDecoder(m_generator.get(), fu
llSize(), &tempDecoder)); | 245 EXPECT_TRUE(ImageDecodingStore::instance().lockDecoder(m_generator.get(), fu
llSize(), &tempDecoder)); |
| 214 ASSERT_TRUE(tempDecoder); | 246 ASSERT_TRUE(tempDecoder); |
| 215 tempDecoder->frameBufferAtIndex(0)->setHasAlpha(false); | 247 tempDecoder->frameBufferAtIndex(0)->setHasAlpha(false); |
| 216 ImageDecodingStore::instance().unlockDecoder(m_generator.get(), tempDecoder)
; | 248 ImageDecodingStore::instance().unlockDecoder(m_generator.get(), tempDecoder)
; |
| 217 EXPECT_EQ(2, m_decodeRequestCount); | 249 EXPECT_EQ(2, m_decodeRequestCount); |
| 218 | 250 |
| 219 setFrameStatus(ImageFrame::FrameComplete); | 251 setFrameStatus(ImageFrame::FrameComplete); |
| 220 m_generator->decodeAndScale(m_segmentReader.get(), false, 0, imageInfo(), bu
ffer, 100 * 4); | 252 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 221 EXPECT_EQ(3, m_decodeRequestCount); | 253 EXPECT_EQ(3, m_decodeRequestCount); |
| 222 EXPECT_FALSE(m_generator->hasAlpha(0)); | 254 EXPECT_FALSE(m_generator->hasAlpha(0)); |
| 223 } | 255 } |
| 224 | 256 |
| 225 TEST_F(ImageFrameGeneratorTest, clearMultiFrameDecoder) | 257 TEST_F(ImageFrameGeneratorTest, clearMultiFrameDecoder) |
| 226 { | 258 { |
| 227 setFrameCount(3); | 259 setFrameCount(3); |
| 228 setFrameStatus(ImageFrame::FrameComplete); | 260 setFrameStatus(ImageFrame::FrameComplete); |
| 229 | 261 |
| 230 char buffer[100 * 100 * 4]; | 262 char buffer[100 * 100 * 4]; |
| 231 m_generator->decodeAndScale(m_segmentReader.get(), true, 0, imageInfo(), buf
fer, 100 * 4); | 263 m_generator->decodeAndScale(0, imageInfo(), buffer, 100 * 4); |
| 232 EXPECT_EQ(1, m_decodeRequestCount); | 264 EXPECT_EQ(1, m_decodeRequestCount); |
| 233 EXPECT_EQ(0, m_decodersDestroyed); | 265 EXPECT_EQ(0, m_decodersDestroyed); |
| 234 EXPECT_EQ(0U, m_requestedClearExceptFrame); | 266 EXPECT_EQ(0U, m_requestedClearExceptFrame); |
| 235 | 267 |
| 236 setFrameStatus(ImageFrame::FrameComplete); | 268 setFrameStatus(ImageFrame::FrameComplete); |
| 237 | 269 |
| 238 m_generator->decodeAndScale(m_segmentReader.get(), true, 1, imageInfo(), buf
fer, 100 * 4); | 270 m_generator->decodeAndScale(1, imageInfo(), buffer, 100 * 4); |
| 239 EXPECT_EQ(2, m_decodeRequestCount); | 271 EXPECT_EQ(2, m_decodeRequestCount); |
| 240 EXPECT_EQ(0, m_decodersDestroyed); | 272 EXPECT_EQ(0, m_decodersDestroyed); |
| 241 EXPECT_EQ(1U, m_requestedClearExceptFrame); | 273 EXPECT_EQ(1U, m_requestedClearExceptFrame); |
| 242 | 274 |
| 243 setFrameStatus(ImageFrame::FrameComplete); | 275 setFrameStatus(ImageFrame::FrameComplete); |
| 244 | 276 |
| 245 // Decoding the last frame of a multi-frame images should trigger clearing | 277 // Decoding the last frame of a multi-frame images should trigger clearing |
| 246 // all the frame data, but not destroying the decoder. See comments in | 278 // all the frame data, but not destroying the decoder. See comments in |
| 247 // ImageFrameGenerator::tryToResumeDecode(). | 279 // ImageFrameGenerator::tryToResumeDecode(). |
| 248 m_generator->decodeAndScale(m_segmentReader.get(), true, 2, imageInfo(), buf
fer, 100 * 4); | 280 m_generator->decodeAndScale(2, imageInfo(), buffer, 100 * 4); |
| 249 EXPECT_EQ(3, m_decodeRequestCount); | 281 EXPECT_EQ(3, m_decodeRequestCount); |
| 250 EXPECT_EQ(0, m_decodersDestroyed); | 282 EXPECT_EQ(0, m_decodersDestroyed); |
| 251 EXPECT_EQ(kNotFound, m_requestedClearExceptFrame); | 283 EXPECT_EQ(kNotFound, m_requestedClearExceptFrame); |
| 252 } | 284 } |
| 253 | 285 |
| 254 } // namespace blink | 286 } // namespace blink |
| OLD | NEW |