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