OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2012 Google Inc. All rights reserved. | |
3 * | |
4 * Redistribution and use in source and binary forms, with or without | |
5 * modification, are permitted provided that the following conditions | |
6 * are met: | |
7 * | |
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. | |
13 * | |
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. | |
24 */ | |
25 | |
26 #include "config.h" | |
27 #include "core/platform/graphics/ImageFrameGenerator.h" | |
28 | |
29 #include "core/platform/graphics/ImageDecodingStore.h" | |
30 #include "core/platform/graphics/test/MockImageDecoder.h" | |
31 #include "platform/SharedBuffer.h" | |
32 #include "platform/Task.h" | |
33 #include "public/platform/Platform.h" | |
34 #include "public/platform/WebThread.h" | |
35 #include <gtest/gtest.h> | |
36 | |
37 namespace WebCore { | |
38 | |
39 namespace { | |
40 | |
41 // Helper methods to generate standard sizes. | |
42 SkISize fullSize() { return SkISize::Make(100, 100); } | |
43 SkISize scaledSize() { return SkISize::Make(50, 50); } | |
44 | |
45 } // namespace | |
46 | |
47 class ImageFrameGeneratorTest : public ::testing::Test, public MockImageDecoderC
lient { | |
48 public: | |
49 virtual void SetUp() OVERRIDE | |
50 { | |
51 ImageDecodingStore::initializeOnce(); | |
52 m_data = SharedBuffer::create(); | |
53 m_generator = ImageFrameGenerator::create(fullSize(), m_data, true); | |
54 useMockImageDecoderFactory(); | |
55 m_decodersDestroyed = 0; | |
56 m_frameBufferRequestCount = 0; | |
57 m_status = ImageFrame::FrameEmpty; | |
58 } | |
59 | |
60 virtual void TearDown() OVERRIDE | |
61 { | |
62 ImageDecodingStore::shutdown(); | |
63 } | |
64 | |
65 virtual void decoderBeingDestroyed() OVERRIDE | |
66 { | |
67 ++m_decodersDestroyed; | |
68 } | |
69 | |
70 virtual void frameBufferRequested() OVERRIDE | |
71 { | |
72 ++m_frameBufferRequestCount; | |
73 } | |
74 | |
75 virtual ImageFrame::Status status() OVERRIDE | |
76 { | |
77 ImageFrame::Status currentStatus = m_status; | |
78 m_status = m_nextFrameStatus; | |
79 return currentStatus; | |
80 } | |
81 | |
82 virtual size_t frameCount() OVERRIDE { return 1; } | |
83 virtual int repetitionCount() const OVERRIDE { return cAnimationNone; } | |
84 virtual float frameDuration() const OVERRIDE { return 0; } | |
85 | |
86 protected: | |
87 void useMockImageDecoderFactory() | |
88 { | |
89 m_generator->setImageDecoderFactory(MockImageDecoderFactory::create(this
, fullSize())); | |
90 } | |
91 | |
92 PassOwnPtr<ScaledImageFragment> createCompleteImage(const SkISize& size) | |
93 { | |
94 SkBitmap bitmap; | |
95 bitmap.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height(
)); | |
96 bitmap.allocPixels(); | |
97 return ScaledImageFragment::createComplete(size, 0, bitmap); | |
98 } | |
99 | |
100 void addNewData() | |
101 { | |
102 m_data->append("g", 1); | |
103 m_generator->setData(m_data, false); | |
104 } | |
105 | |
106 void setFrameStatus(ImageFrame::Status status) { m_status = m_nextFrameStat
us = status; } | |
107 void setNextFrameStatus(ImageFrame::Status status) { m_nextFrameStatus = st
atus; } | |
108 | |
109 SkBitmap::Allocator* allocator() const { return m_generator->allocator(); } | |
110 void setAllocator(PassOwnPtr<SkBitmap::Allocator> allocator) | |
111 { | |
112 m_generator->setAllocator(allocator); | |
113 } | |
114 | |
115 PassOwnPtr<ScaledImageFragment> decode(size_t index) | |
116 { | |
117 ImageDecoder* decoder = 0; | |
118 return m_generator->decode(index, &decoder); | |
119 } | |
120 | |
121 RefPtr<SharedBuffer> m_data; | |
122 RefPtr<ImageFrameGenerator> m_generator; | |
123 int m_decodersDestroyed; | |
124 int m_frameBufferRequestCount; | |
125 ImageFrame::Status m_status; | |
126 ImageFrame::Status m_nextFrameStatus; | |
127 }; | |
128 | |
129 TEST_F(ImageFrameGeneratorTest, cacheHit) | |
130 { | |
131 const ScaledImageFragment* fullImage = ImageDecodingStore::instance()->inser
tAndLockCache( | |
132 m_generator.get(), createCompleteImage(fullSize())); | |
133 EXPECT_EQ(fullSize(), fullImage->scaledSize()); | |
134 ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); | |
135 | |
136 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize(
)); | |
137 EXPECT_EQ(fullImage, tempImage); | |
138 EXPECT_EQ(fullSize(), tempImage->scaledSize()); | |
139 EXPECT_TRUE(m_generator->hasAlpha(0)); | |
140 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
141 EXPECT_EQ(0, m_frameBufferRequestCount); | |
142 } | |
143 | |
144 TEST_F(ImageFrameGeneratorTest, cacheMissWithScale) | |
145 { | |
146 const ScaledImageFragment* fullImage = ImageDecodingStore::instance()->inser
tAndLockCache( | |
147 m_generator.get(), createCompleteImage(fullSize())); | |
148 EXPECT_EQ(fullSize(), fullImage->scaledSize()); | |
149 ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); | |
150 | |
151 // Cache miss because of scaled size not found. | |
152 const ScaledImageFragment* scaledImage = m_generator->decodeAndScale(scaledS
ize()); | |
153 EXPECT_NE(fullImage, scaledImage); | |
154 EXPECT_EQ(scaledSize(), scaledImage->scaledSize()); | |
155 EXPECT_TRUE(m_generator->hasAlpha(0)); | |
156 ImageDecodingStore::instance()->unlockCache(m_generator.get(), scaledImage); | |
157 | |
158 // Cache hit. | |
159 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(scaledSiz
e()); | |
160 EXPECT_EQ(scaledImage, tempImage); | |
161 EXPECT_EQ(scaledSize(), tempImage->scaledSize()); | |
162 EXPECT_TRUE(m_generator->hasAlpha(0)); | |
163 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
164 EXPECT_EQ(0, m_frameBufferRequestCount); | |
165 } | |
166 | |
167 TEST_F(ImageFrameGeneratorTest, cacheMissWithDecodeAndScale) | |
168 { | |
169 setFrameStatus(ImageFrame::FrameComplete); | |
170 | |
171 // Cache miss. | |
172 const ScaledImageFragment* scaledImage = m_generator->decodeAndScale(scaledS
ize()); | |
173 EXPECT_EQ(1, m_frameBufferRequestCount); | |
174 EXPECT_EQ(scaledSize(), scaledImage->scaledSize()); | |
175 EXPECT_FALSE(m_generator->hasAlpha(0)); | |
176 ImageDecodingStore::instance()->unlockCache(m_generator.get(), scaledImage); | |
177 EXPECT_EQ(1, m_decodersDestroyed); | |
178 | |
179 // Cache hit. | |
180 const ScaledImageFragment* fullImage = m_generator->decodeAndScale(fullSize(
)); | |
181 EXPECT_NE(scaledImage, fullImage); | |
182 EXPECT_EQ(fullSize(), fullImage->scaledSize()); | |
183 EXPECT_FALSE(m_generator->hasAlpha(0)); | |
184 ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); | |
185 | |
186 // Cache hit. | |
187 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(scaledSiz
e()); | |
188 EXPECT_EQ(scaledImage, tempImage); | |
189 EXPECT_EQ(scaledSize(), tempImage->scaledSize()); | |
190 EXPECT_FALSE(m_generator->hasAlpha(0)); | |
191 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
192 EXPECT_EQ(1, m_frameBufferRequestCount); | |
193 } | |
194 | |
195 TEST_F(ImageFrameGeneratorTest, cacheMissWithIncompleteDecode) | |
196 { | |
197 setFrameStatus(ImageFrame::FramePartial); | |
198 | |
199 const ScaledImageFragment* tempImage= m_generator->decodeAndScale(fullSize()
); | |
200 EXPECT_FALSE(tempImage->isComplete()); | |
201 EXPECT_EQ(1, m_frameBufferRequestCount); | |
202 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
203 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); | |
204 EXPECT_EQ(1, ImageDecodingStore::instance()->imageCacheEntries()); | |
205 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); | |
206 | |
207 addNewData(); | |
208 tempImage = m_generator->decodeAndScale(fullSize()); | |
209 EXPECT_FALSE(tempImage->isComplete()); | |
210 EXPECT_EQ(2, m_frameBufferRequestCount); | |
211 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
212 EXPECT_EQ(3, ImageDecodingStore::instance()->cacheEntries()); | |
213 EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); | |
214 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); | |
215 EXPECT_EQ(0, m_decodersDestroyed); | |
216 } | |
217 | |
218 TEST_F(ImageFrameGeneratorTest, cacheMissWithIncompleteDecodeAndScale) | |
219 { | |
220 setFrameStatus(ImageFrame::FramePartial); | |
221 | |
222 const ScaledImageFragment* tempImage= m_generator->decodeAndScale(scaledSize
()); | |
223 EXPECT_FALSE(tempImage->isComplete()); | |
224 EXPECT_EQ(1, m_frameBufferRequestCount); | |
225 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
226 EXPECT_EQ(3, ImageDecodingStore::instance()->cacheEntries()); | |
227 EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); | |
228 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); | |
229 | |
230 addNewData(); | |
231 tempImage = m_generator->decodeAndScale(scaledSize()); | |
232 EXPECT_FALSE(tempImage->isComplete()); | |
233 EXPECT_EQ(2, m_frameBufferRequestCount); | |
234 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
235 EXPECT_EQ(5, ImageDecodingStore::instance()->cacheEntries()); | |
236 EXPECT_EQ(4, ImageDecodingStore::instance()->imageCacheEntries()); | |
237 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); | |
238 EXPECT_EQ(0, m_decodersDestroyed); | |
239 } | |
240 | |
241 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesComplete) | |
242 { | |
243 setFrameStatus(ImageFrame::FramePartial); | |
244 | |
245 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize(
)); | |
246 EXPECT_FALSE(tempImage->isComplete()); | |
247 EXPECT_EQ(1, m_frameBufferRequestCount); | |
248 EXPECT_EQ(0, m_decodersDestroyed); | |
249 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
250 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); | |
251 EXPECT_EQ(1, ImageDecodingStore::instance()->imageCacheEntries()); | |
252 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); | |
253 | |
254 setFrameStatus(ImageFrame::FrameComplete); | |
255 addNewData(); | |
256 | |
257 tempImage = m_generator->decodeAndScale(fullSize()); | |
258 EXPECT_TRUE(tempImage->isComplete()); | |
259 EXPECT_EQ(2, m_frameBufferRequestCount); | |
260 EXPECT_EQ(1, m_decodersDestroyed); | |
261 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
262 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); | |
263 EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); | |
264 EXPECT_EQ(0, ImageDecodingStore::instance()->decoderCacheEntries()); | |
265 | |
266 tempImage = m_generator->decodeAndScale(fullSize()); | |
267 EXPECT_TRUE(tempImage->isComplete()); | |
268 EXPECT_EQ(2, m_frameBufferRequestCount); | |
269 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
270 } | |
271 | |
272 TEST_F(ImageFrameGeneratorTest, incompleteDecodeAndScaleBecomesComplete) | |
273 { | |
274 setFrameStatus(ImageFrame::FramePartial); | |
275 | |
276 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(scaledSiz
e()); | |
277 EXPECT_FALSE(tempImage->isComplete()); | |
278 EXPECT_EQ(1, m_frameBufferRequestCount); | |
279 EXPECT_EQ(0, m_decodersDestroyed); | |
280 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
281 EXPECT_EQ(3, ImageDecodingStore::instance()->cacheEntries()); | |
282 EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); | |
283 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); | |
284 | |
285 setFrameStatus(ImageFrame::FrameComplete); | |
286 addNewData(); | |
287 | |
288 tempImage = m_generator->decodeAndScale(scaledSize()); | |
289 EXPECT_TRUE(tempImage->isComplete()); | |
290 EXPECT_EQ(2, m_frameBufferRequestCount); | |
291 EXPECT_EQ(1, m_decodersDestroyed); | |
292 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
293 EXPECT_EQ(4, ImageDecodingStore::instance()->cacheEntries()); | |
294 EXPECT_EQ(4, ImageDecodingStore::instance()->imageCacheEntries()); | |
295 EXPECT_EQ(0, ImageDecodingStore::instance()->decoderCacheEntries()); | |
296 | |
297 tempImage = m_generator->decodeAndScale(scaledSize()); | |
298 EXPECT_TRUE(tempImage->isComplete()); | |
299 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
300 | |
301 tempImage = m_generator->decodeAndScale(fullSize()); | |
302 EXPECT_TRUE(tempImage->isComplete()); | |
303 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
304 | |
305 EXPECT_EQ(2, m_frameBufferRequestCount); | |
306 } | |
307 | |
308 static void decodeThreadMain(ImageFrameGenerator* generator) | |
309 { | |
310 const ScaledImageFragment* tempImage = generator->decodeAndScale(fullSize())
; | |
311 ImageDecodingStore::instance()->unlockCache(generator, tempImage); | |
312 } | |
313 | |
314 TEST_F(ImageFrameGeneratorTest, incompleteDecodeBecomesCompleteMultiThreaded) | |
315 { | |
316 setFrameStatus(ImageFrame::FramePartial); | |
317 | |
318 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize(
)); | |
319 EXPECT_FALSE(tempImage->isComplete()); | |
320 EXPECT_EQ(1, m_frameBufferRequestCount); | |
321 EXPECT_EQ(0, m_decodersDestroyed); | |
322 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
323 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); | |
324 EXPECT_EQ(1, ImageDecodingStore::instance()->imageCacheEntries()); | |
325 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); | |
326 | |
327 // Frame can now be decoded completely. | |
328 setFrameStatus(ImageFrame::FrameComplete); | |
329 addNewData(); | |
330 OwnPtr<blink::WebThread> thread = adoptPtr(blink::Platform::current()->creat
eThread("DecodeThread")); | |
331 thread->postTask(new Task(WTF::bind(&decodeThreadMain, m_generator.get()))); | |
332 thread.clear(); | |
333 | |
334 EXPECT_EQ(2, m_frameBufferRequestCount); | |
335 EXPECT_EQ(1, m_decodersDestroyed); | |
336 EXPECT_EQ(2, ImageDecodingStore::instance()->cacheEntries()); | |
337 EXPECT_EQ(2, ImageDecodingStore::instance()->imageCacheEntries()); | |
338 EXPECT_EQ(0, ImageDecodingStore::instance()->decoderCacheEntries()); | |
339 | |
340 tempImage = m_generator->decodeAndScale(fullSize()); | |
341 EXPECT_TRUE(tempImage->isComplete()); | |
342 EXPECT_EQ(2, m_frameBufferRequestCount); | |
343 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
344 } | |
345 | |
346 TEST_F(ImageFrameGeneratorTest, concurrentIncompleteDecodeAndScale) | |
347 { | |
348 setFrameStatus(ImageFrame::FramePartial); | |
349 | |
350 const ScaledImageFragment* fullImage = m_generator->decodeAndScale(fullSize(
)); | |
351 const ScaledImageFragment* scaledImage = m_generator->decodeAndScale(scaledS
ize()); | |
352 EXPECT_FALSE(fullImage->isComplete()); | |
353 EXPECT_FALSE(scaledImage->isComplete()); | |
354 EXPECT_EQ(2, m_frameBufferRequestCount); | |
355 ImageDecodingStore::instance()->unlockCache(m_generator.get(), fullImage); | |
356 ImageDecodingStore::instance()->unlockCache(m_generator.get(), scaledImage); | |
357 EXPECT_EQ(4, ImageDecodingStore::instance()->cacheEntries()); | |
358 EXPECT_EQ(3, ImageDecodingStore::instance()->imageCacheEntries()); | |
359 EXPECT_EQ(1, ImageDecodingStore::instance()->decoderCacheEntries()); | |
360 EXPECT_EQ(0, m_decodersDestroyed); | |
361 | |
362 addNewData(); | |
363 setFrameStatus(ImageFrame::FrameComplete); | |
364 scaledImage = m_generator->decodeAndScale(scaledSize()); | |
365 EXPECT_TRUE(scaledImage->isComplete()); | |
366 EXPECT_EQ(3, m_frameBufferRequestCount); | |
367 ImageDecodingStore::instance()->unlockCache(m_generator.get(), scaledImage); | |
368 EXPECT_EQ(5, ImageDecodingStore::instance()->cacheEntries()); | |
369 EXPECT_EQ(5, ImageDecodingStore::instance()->imageCacheEntries()); | |
370 EXPECT_EQ(0, ImageDecodingStore::instance()->decoderCacheEntries()); | |
371 EXPECT_EQ(1, m_decodersDestroyed); | |
372 } | |
373 | |
374 TEST_F(ImageFrameGeneratorTest, incompleteBitmapCopied) | |
375 { | |
376 setFrameStatus(ImageFrame::FramePartial); | |
377 | |
378 const ScaledImageFragment* tempImage= m_generator->decodeAndScale(fullSize()
); | |
379 EXPECT_FALSE(tempImage->isComplete()); | |
380 EXPECT_EQ(1, m_frameBufferRequestCount); | |
381 | |
382 ImageDecoder* tempDecoder = 0; | |
383 EXPECT_TRUE(ImageDecodingStore::instance()->lockDecoder(m_generator.get(), f
ullSize(), &tempDecoder)); | |
384 ASSERT_TRUE(tempDecoder); | |
385 EXPECT_NE(tempDecoder->frameBufferAtIndex(0)->getSkBitmap().getPixels(), tem
pImage->bitmap().getPixels()); | |
386 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
387 ImageDecodingStore::instance()->unlockDecoder(m_generator.get(), tempDecoder
); | |
388 } | |
389 | |
390 TEST_F(ImageFrameGeneratorTest, resumeDecodeEmptyFrameTurnsComplete) | |
391 { | |
392 m_generator = ImageFrameGenerator::create(fullSize(), m_data, false, true); | |
393 useMockImageDecoderFactory(); | |
394 setFrameStatus(ImageFrame::FrameComplete); | |
395 | |
396 const ScaledImageFragment* tempImage = m_generator->decodeAndScale(fullSize(
), 0); | |
397 EXPECT_TRUE(tempImage->isComplete()); | |
398 ImageDecodingStore::instance()->unlockCache(m_generator.get(), tempImage); | |
399 | |
400 setFrameStatus(ImageFrame::FrameEmpty); | |
401 setNextFrameStatus(ImageFrame::FrameComplete); | |
402 EXPECT_FALSE(m_generator->decodeAndScale(fullSize(), 1)); | |
403 } | |
404 | |
405 TEST_F(ImageFrameGeneratorTest, frameHasAlpha) | |
406 { | |
407 setFrameStatus(ImageFrame::FramePartial); | |
408 ImageDecodingStore::instance()->unlockCache(m_generator.get(), m_generator->
decodeAndScale(fullSize(), 1)); | |
409 EXPECT_TRUE(m_generator->hasAlpha(1)); | |
410 | |
411 ImageDecoder* tempDecoder = 0; | |
412 EXPECT_TRUE(ImageDecodingStore::instance()->lockDecoder(m_generator.get(), f
ullSize(), &tempDecoder)); | |
413 ASSERT_TRUE(tempDecoder); | |
414 static_cast<MockImageDecoder*>(tempDecoder)->setFrameHasAlpha(false); | |
415 ImageDecodingStore::instance()->unlockDecoder(m_generator.get(), tempDecoder
); | |
416 | |
417 setFrameStatus(ImageFrame::FrameComplete); | |
418 ImageDecodingStore::instance()->unlockCache(m_generator.get(), m_generator->
decodeAndScale(fullSize(), 1)); | |
419 EXPECT_FALSE(m_generator->hasAlpha(1)); | |
420 } | |
421 | |
422 namespace { | |
423 | |
424 class MockAllocator : public SkBitmap::Allocator { | |
425 public: | |
426 // N starts from 0. | |
427 MockAllocator(int failAtNthCall) | |
428 : m_callCount(0) | |
429 , m_failAtNthCall(failAtNthCall) | |
430 , m_defaultAllocator(adoptPtr(new DiscardablePixelRefAllocator())) | |
431 { | |
432 } | |
433 | |
434 virtual bool allocPixelRef(SkBitmap* bitmap, SkColorTable* colorTable) OVERR
IDE | |
435 { | |
436 if (m_callCount++ == m_failAtNthCall) | |
437 return false; | |
438 return m_defaultAllocator->allocPixelRef(bitmap, colorTable); | |
439 } | |
440 | |
441 int m_callCount; | |
442 int m_failAtNthCall; | |
443 OwnPtr<SkBitmap::Allocator> m_defaultAllocator; | |
444 }; | |
445 | |
446 } // namespace | |
447 | |
448 TEST_F(ImageFrameGeneratorTest, decodingAllocatorFailure) | |
449 { | |
450 // Try to emulate allocation failures at different stages. For now, the | |
451 // first allocation is for the bitmap in ImageFrame, the second is for the | |
452 // copy of partial bitmap. The loop will still work if the number or purpose | |
453 // of allocations change in the future. | |
454 for (int i = 0; ; ++i) { | |
455 SCOPED_TRACE(testing::Message() << "Allocation failure at call " << i); | |
456 setFrameStatus(ImageFrame::FramePartial); | |
457 setAllocator(adoptPtr(new MockAllocator(i))); | |
458 OwnPtr<ScaledImageFragment> image = decode(0); | |
459 if (i >= static_cast<MockAllocator*>(allocator())->m_callCount) { | |
460 // We have tested failures of all stages. This time all allocations | |
461 // were successful. | |
462 EXPECT_TRUE(image); | |
463 break; | |
464 } | |
465 EXPECT_FALSE(image); | |
466 } | |
467 } | |
468 | |
469 } // namespace WebCore | |
OLD | NEW |