OLD | NEW |
---|---|
1 /* | 1 /* |
2 * Copyright (c) 2013, Google Inc. All rights reserved. | 2 * Copyright (c) 2013, 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 are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * 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 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 20 matching lines...) Expand all Loading... | |
31 #include "platform/graphics/BitmapImage.h" | 31 #include "platform/graphics/BitmapImage.h" |
32 | 32 |
33 #include "platform/SharedBuffer.h" | 33 #include "platform/SharedBuffer.h" |
34 #include "platform/graphics/BitmapImageMetrics.h" | 34 #include "platform/graphics/BitmapImageMetrics.h" |
35 #include "platform/graphics/DeferredImageDecoder.h" | 35 #include "platform/graphics/DeferredImageDecoder.h" |
36 #include "platform/graphics/ImageObserver.h" | 36 #include "platform/graphics/ImageObserver.h" |
37 #include "platform/testing/HistogramTester.h" | 37 #include "platform/testing/HistogramTester.h" |
38 #include "platform/testing/UnitTestHelpers.h" | 38 #include "platform/testing/UnitTestHelpers.h" |
39 #include "testing/gtest/include/gtest/gtest.h" | 39 #include "testing/gtest/include/gtest/gtest.h" |
40 | 40 |
41 #define BITMAP_IMAGE_TEST 1 | |
Peter Kasting
2016/04/28 23:07:54
Don't add this.
aleksandar.stojiljkovic
2016/04/29 17:17:43
Done.
| |
42 | |
41 namespace blink { | 43 namespace blink { |
42 | 44 |
43 class BitmapImageTest : public ::testing::Test { | 45 class BitmapImageTest : public ::testing::Test { |
44 public: | 46 public: |
45 class FakeImageObserver : public GarbageCollectedFinalized<FakeImageObserver >, public ImageObserver { | 47 class FakeImageObserver : public GarbageCollectedFinalized<FakeImageObserver >, public ImageObserver { |
46 USING_GARBAGE_COLLECTED_MIXIN(FakeImageObserver); | 48 USING_GARBAGE_COLLECTED_MIXIN(FakeImageObserver); |
47 public: | 49 public: |
48 FakeImageObserver() : m_lastDecodedSizeChangedDelta(0) { } | 50 FakeImageObserver() : m_lastDecodedSizeChangedDelta(0) { } |
49 | 51 |
50 virtual void decodedSizeChanged(const Image*, int delta) | 52 virtual void decodedSizeChanged(const Image*, int delta) |
(...skipping 13 matching lines...) Expand all Loading... | |
64 BitmapImageTest(bool enableDeferredDecoding) : m_enableDeferredDecoding(enab leDeferredDecoding) { } | 66 BitmapImageTest(bool enableDeferredDecoding) : m_enableDeferredDecoding(enab leDeferredDecoding) { } |
65 | 67 |
66 static PassRefPtr<SharedBuffer> readFile(const char* fileName) | 68 static PassRefPtr<SharedBuffer> readFile(const char* fileName) |
67 { | 69 { |
68 String filePath = testing::blinkRootDir(); | 70 String filePath = testing::blinkRootDir(); |
69 filePath.append(fileName); | 71 filePath.append(fileName); |
70 return testing::readFromFile(filePath); | 72 return testing::readFromFile(filePath); |
71 } | 73 } |
72 | 74 |
73 // Accessors to BitmapImage's protected methods. | 75 // Accessors to BitmapImage's protected methods. |
74 void destroyDecodedData(bool destroyAll) { m_image->destroyDecodedData(destr oyAll); } | 76 void destroyDecodedData() { m_image->destroyDecodedData(); } |
75 size_t frameCount() { return m_image->frameCount(); } | 77 size_t frameCount() { return m_image->frameCount(); } |
76 void frameAtIndex(size_t index) | 78 PassRefPtr<SkImage> frameAtIndex(size_t index) |
77 { | 79 { |
78 m_image->frameAtIndex(index); | 80 return m_image->frameAtIndex(index); |
79 } | 81 } |
80 void setCurrentFrame(size_t frame) { m_image->m_currentFrame = frame; } | 82 void setCurrentFrame(size_t frame) { m_image->m_currentFrame = frame; } |
81 size_t frameDecodedSize(size_t frame) { return m_image->m_frames[frame].m_fr ameBytes; } | 83 size_t frameDecodedSize(size_t frame) { return m_image->m_frames[frame].m_fr ameBytes; } |
82 size_t decodedFramesCount() const { return m_image->m_frames.size(); } | 84 size_t decodedFramesCount() const { return m_image->m_frames.size(); } |
83 | 85 |
84 void setFirstFrameNotComplete() { m_image->m_frames[0].m_isComplete = false; } | 86 void setFirstFrameNotComplete() { m_image->m_frames[0].m_isComplete = false; } |
85 | 87 |
86 void loadImage(const char* fileName, bool loadAllFrames = true) | 88 void loadImage(const char* fileName, bool loadAllFrames = true) |
87 { | 89 { |
88 RefPtr<SharedBuffer> imageData = readFile(fileName); | 90 RefPtr<SharedBuffer> imageData = readFile(fileName); |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
125 int animationFinished() | 127 int animationFinished() |
126 { | 128 { |
127 return m_image->m_animationFinished; | 129 return m_image->m_animationFinished; |
128 } | 130 } |
129 | 131 |
130 PassRefPtr<Image> imageForDefaultFrame() | 132 PassRefPtr<Image> imageForDefaultFrame() |
131 { | 133 { |
132 return m_image->imageForDefaultFrame(); | 134 return m_image->imageForDefaultFrame(); |
133 } | 135 } |
134 | 136 |
137 void setAnimationCacheSizeForTesting(size_t maxCacheSize, size_t maxAnimatio nSizeInCache) | |
138 { | |
139 BitmapImage::setAnimationCacheSizeForTesting(maxCacheSize, maxAnimationS izeInCache); | |
140 } | |
141 | |
142 int lastDecodedSizeChange() | |
143 { | |
144 return m_imageObserver->m_lastDecodedSizeChangedDelta; | |
145 } | |
146 | |
135 protected: | 147 protected: |
136 void SetUp() override | 148 void SetUp() override |
137 { | 149 { |
138 DeferredImageDecoder::setEnabled(m_enableDeferredDecoding); | 150 DeferredImageDecoder::setEnabled(m_enableDeferredDecoding); |
139 m_imageObserver = new FakeImageObserver; | 151 m_imageObserver = new FakeImageObserver; |
140 m_image = BitmapImage::create(m_imageObserver.get()); | 152 m_image = BitmapImage::create(m_imageObserver.get()); |
141 } | 153 } |
142 | 154 |
143 Persistent<FakeImageObserver> m_imageObserver; | 155 Persistent<FakeImageObserver> m_imageObserver; |
144 RefPtr<BitmapImage> m_image; | 156 RefPtr<BitmapImage> m_image; |
145 | 157 |
146 private: | 158 private: |
147 bool m_enableDeferredDecoding; | 159 bool m_enableDeferredDecoding; |
148 }; | 160 }; |
149 | 161 |
150 TEST_F(BitmapImageTest, destroyDecodedDataExceptCurrentFrame) | |
151 { | |
152 loadImage("/LayoutTests/fast/images/resources/animated-10color.gif"); | |
153 size_t totalSize = decodedSize(); | |
154 size_t frame = frameCount() / 2; | |
155 setCurrentFrame(frame); | |
156 size_t size = frameDecodedSize(frame); | |
157 destroyDecodedData(false); | |
158 EXPECT_LT(m_imageObserver->m_lastDecodedSizeChangedDelta, 0); | |
159 EXPECT_GE(m_imageObserver->m_lastDecodedSizeChangedDelta, -static_cast<int>( totalSize - size)); | |
160 } | |
161 | |
162 TEST_F(BitmapImageTest, destroyAllDecodedData) | 162 TEST_F(BitmapImageTest, destroyAllDecodedData) |
Peter Kasting
2016/04/28 23:07:54
Nit: Remove "All"?
aleksandar.stojiljkovic
2016/04/29 17:17:43
Done.
| |
163 { | 163 { |
164 loadImage("/LayoutTests/fast/images/resources/animated-10color.gif"); | 164 loadImage("/LayoutTests/fast/images/resources/animated-10color.gif"); |
165 size_t totalSize = decodedSize(); | 165 size_t totalSize = decodedSize(); |
166 EXPECT_GT(totalSize, 0u); | 166 EXPECT_GT(totalSize, 0u); |
167 destroyDecodedData(true); | 167 destroyDecodedData(); |
168 EXPECT_EQ(-static_cast<int>(totalSize), m_imageObserver->m_lastDecodedSizeCh angedDelta); | 168 EXPECT_EQ(-static_cast<int>(totalSize), lastDecodedSizeChange()); |
169 EXPECT_EQ(0u, decodedSize()); | 169 EXPECT_EQ(0u, decodedSize()); |
170 } | 170 } |
171 | 171 |
172 TEST_F(BitmapImageTest, maybeAnimated) | 172 TEST_F(BitmapImageTest, maybeAnimated) |
173 { | 173 { |
174 loadImage("/LayoutTests/fast/images/resources/gif-loop-count.gif"); | 174 loadImage("/LayoutTests/fast/images/resources/gif-loop-count.gif"); |
175 for (size_t i = 0; i < frameCount(); ++i) { | 175 for (size_t i = 0; i < frameCount(); ++i) { |
176 EXPECT_TRUE(m_image->maybeAnimated()); | 176 EXPECT_TRUE(m_image->maybeAnimated()); |
177 advanceAnimation(); | 177 advanceAnimation(); |
178 } | 178 } |
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
260 } | 260 } |
261 | 261 |
262 TEST_F(BitmapImageTest, correctDecodedDataSize) | 262 TEST_F(BitmapImageTest, correctDecodedDataSize) |
263 { | 263 { |
264 // When requesting a frame of a multi-frame GIF causes another frame to be | 264 // When requesting a frame of a multi-frame GIF causes another frame to be |
265 // decoded as well, both frames' sizes should be reported by the source and | 265 // decoded as well, both frames' sizes should be reported by the source and |
266 // thus included in the decoded size changed notification. | 266 // thus included in the decoded size changed notification. |
267 loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false); | 267 loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false); |
268 frameAtIndex(1); | 268 frameAtIndex(1); |
269 int frameSize = static_cast<int>(m_image->size().area() * sizeof(ImageFrame: :PixelData)); | 269 int frameSize = static_cast<int>(m_image->size().area() * sizeof(ImageFrame: :PixelData)); |
270 EXPECT_EQ(frameSize * 2, m_imageObserver->m_lastDecodedSizeChangedDelta); | 270 EXPECT_EQ(frameSize * 2, lastDecodedSizeChange()); |
271 | |
272 // Trying to destroy all data except an undecoded frame should cause the | |
273 // decoder to seek backwards and preserve the most recent previous frame | |
274 // necessary to decode that undecoded frame, and destroy all other frames. | |
275 setCurrentFrame(2); | |
276 destroyDecodedData(false); | |
277 EXPECT_EQ(-frameSize, m_imageObserver->m_lastDecodedSizeChangedDelta); | |
278 } | 271 } |
279 | 272 |
280 TEST_F(BitmapImageTest, recachingFrameAfterDataChanged) | 273 TEST_F(BitmapImageTest, recachingFrameAfterDataChanged) |
281 { | 274 { |
282 loadImage("/LayoutTests/fast/images/resources/green.jpg"); | 275 loadImage("/LayoutTests/fast/images/resources/green.jpg"); |
283 setFirstFrameNotComplete(); | 276 setFirstFrameNotComplete(); |
284 EXPECT_GT(m_imageObserver->m_lastDecodedSizeChangedDelta, 0); | 277 EXPECT_GT(lastDecodedSizeChange(), 0); |
285 m_imageObserver->m_lastDecodedSizeChangedDelta = 0; | 278 m_imageObserver->m_lastDecodedSizeChangedDelta = 0; |
286 | 279 |
287 // Calling dataChanged causes the cache to flush, but doesn't affect the | 280 // Calling dataChanged causes the cache to flush, but doesn't affect the |
288 // source's decoded frames. It shouldn't affect decoded size. | 281 // source's decoded frames. It shouldn't affect decoded size. |
289 m_image->dataChanged(true); | 282 m_image->dataChanged(true); |
290 EXPECT_EQ(0, m_imageObserver->m_lastDecodedSizeChangedDelta); | 283 EXPECT_EQ(0, lastDecodedSizeChange()); |
291 // Recaching the first frame also shouldn't affect decoded size. | 284 // Recaching the first frame also shouldn't affect decoded size. |
292 m_image->imageForCurrentFrame(); | 285 m_image->imageForCurrentFrame(); |
293 EXPECT_EQ(0, m_imageObserver->m_lastDecodedSizeChangedDelta); | 286 EXPECT_EQ(0, lastDecodedSizeChange()); |
294 } | 287 } |
295 | 288 |
296 class BitmapImageDeferredDecodingTest : public BitmapImageTest { | 289 class BitmapImageDeferredDecodingTest : public BitmapImageTest { |
297 public: | 290 public: |
298 BitmapImageDeferredDecodingTest() : BitmapImageTest(true) { } | 291 BitmapImageDeferredDecodingTest() : BitmapImageTest(true) { } |
299 }; | 292 }; |
300 | 293 |
294 class BitmapImageTestEmptyImpl : public BitmapImageTest { | |
295 public: | |
296 BitmapImageTestEmptyImpl() : BitmapImageTest(true) | |
297 { | |
298 SetUp(); | |
299 } | |
300 | |
301 void TestBody() override | |
302 { | |
303 } | |
304 }; | |
305 | |
306 TEST_F(BitmapImageDeferredDecodingTest, animationBitmapImageCacheMaxPerAnimation ) | |
307 { | |
308 loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false); | |
309 uint32_t image0 = frameAtIndex(0)->uniqueID(); | |
310 int frameSize = static_cast<int>(m_image->size().area() * sizeof(ImageFrame: :PixelData)); | |
Peter Kasting
2016/04/28 23:07:54
Nit: Should be size_t with no cast since that's wh
aleksandar.stojiljkovic
2016/04/29 17:17:43
This method is removed in patch#2 so Done applies
| |
311 setAnimationCacheSizeForTesting(frameSize * 4, frameSize * 2); | |
312 | |
313 uint32_t image1 = frameAtIndex(1)->uniqueID(); | |
314 uint32_t image0v1 = frameAtIndex(0)->uniqueID(); | |
Peter Kasting
2016/04/28 23:07:55
Nit: Inline into next statement
| |
315 EXPECT_EQ(image0, image0v1); | |
316 uint32_t image2 = frameAtIndex(2)->uniqueID(); | |
317 uint32_t image1v1 = frameAtIndex(1)->uniqueID(); | |
Peter Kasting
2016/04/28 23:07:54
Nit: Inline into next statement
| |
318 // It is expected that 0 and 1 is kept in the cache, and 2 is not cached | |
319 // as only first two frames are cached. | |
320 EXPECT_EQ(image1, image1v1); | |
321 uint32_t image2v1 = frameAtIndex(2)->uniqueID(); | |
Peter Kasting
2016/04/28 23:07:54
Nit: Inline into next statement
| |
322 EXPECT_NE(image2, image2v1); | |
323 } | |
324 | |
325 TEST_F(BitmapImageDeferredDecodingTest, animationBitmapImageCacheEvict) | |
326 { | |
327 loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false); | |
328 uint32_t image0 = frameAtIndex(0)->uniqueID(); | |
329 int frameSize = static_cast<int>(m_image->size().area() * sizeof(ImageFrame: :PixelData)); | |
330 setAnimationCacheSizeForTesting(frameSize * 2, frameSize * 2); | |
331 | |
332 // Load another animation that would evict first animation frames | |
Peter Kasting
2016/04/28 23:07:54
Nit: Trailing period
| |
333 BitmapImageTestEmptyImpl second; | |
334 second.loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false); | |
335 uint32_t second0 = second.frameAtIndex(0)->uniqueID(); | |
336 | |
337 uint32_t image0v1 = frameAtIndex(0)->uniqueID(); | |
338 EXPECT_EQ(image0, image0v1); | |
339 | |
340 uint32_t second0v1 = second.frameAtIndex(0)->uniqueID(); | |
341 EXPECT_EQ(second0, second0v1); | |
342 second.frameAtIndex(1); | |
343 | |
344 // Second 0 and second 1 are now in the cache. | |
345 uint32_t image0v2 = frameAtIndex(0)->uniqueID(); | |
346 EXPECT_NE(image0v1, image0v2); | |
Peter Kasting
2016/04/28 23:07:54
Nit: Compare to |image0| so |image0v1| above can b
| |
347 | |
348 // Second was evicted as original frame 0 + second 2 frames are above cache | |
349 // size even second itself is under per animation limit size. | |
Peter Kasting
2016/04/28 23:07:55
This sentence has grammar issues severe enough tha
| |
350 uint32_t second0v2 = second.frameAtIndex(0)->uniqueID(); | |
351 EXPECT_NE(second0v1, second0v2); | |
Peter Kasting
2016/04/28 23:07:54
Nit: Compare to |second0| so |second0v1| above can
| |
352 | |
353 uint32_t image0v3 = frameAtIndex(0)->uniqueID(); | |
354 EXPECT_EQ(image0v2, image0v3); | |
355 uint32_t second0v3 = second.frameAtIndex(0)->uniqueID(); | |
356 EXPECT_EQ(second0v2, second0v3); | |
357 | |
358 // By setAnimationCacheSizeForTesting it is defined to keep in cache first | |
359 // two frames per animation. Other frames, like frame 2 is cached only | |
360 // temporarily, until access to some other frame. | |
361 // When making space for frame 2 it in cache, the very same ImageBitmap that | |
362 // contains this frame will first get cleared and removed from cache (as it | |
363 // is first for removal in MRU cache), frame index 2 added to it and cached. | |
Peter Kasting
2016/04/28 23:07:54
Similarly this whole comment has significant gramm
| |
364 frameAtIndex(2); | |
365 uint32_t image0v4 = frameAtIndex(0)->uniqueID(); | |
366 EXPECT_NE(image0v3, image0v4); | |
Peter Kasting
2016/04/28 23:07:55
Nit: Compare to |image0v2| so |image0v3| above can
| |
367 uint32_t second0v4 = second.frameAtIndex(0)->uniqueID(); | |
368 EXPECT_EQ(second0v3, second0v4); | |
Peter Kasting
2016/04/28 23:07:54
Nit: Compare to |second0v2| so |second0v3| above c
| |
369 | |
370 BitmapImageTestEmptyImpl third; | |
371 third.loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false); | |
372 third.frameAtIndex(0); // It should evict image0v4. | |
373 uint32_t image0v5 = frameAtIndex(0)->uniqueID(); | |
Peter Kasting
2016/04/28 23:07:54
Nit: Inline into next statement
| |
374 EXPECT_NE(image0v4, image0v5); | |
375 } | |
376 | |
301 TEST_F(BitmapImageDeferredDecodingTest, correctDecodedDataSize) | 377 TEST_F(BitmapImageDeferredDecodingTest, correctDecodedDataSize) |
302 { | 378 { |
303 // When deferred decoding is enabled, requesting any one frame shouldn't | 379 // When deferred decoding is enabled, requesting any one frame shouldn't |
304 // result in decoding any other frames. | 380 // result in decoding any other frames. |
305 loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false); | 381 loadImage("/LayoutTests/fast/images/resources/anim_none.gif", false); |
306 frameAtIndex(1); | 382 frameAtIndex(1); |
307 int frameSize = static_cast<int>(m_image->size().area() * sizeof(ImageFrame: :PixelData)); | 383 int frameSize = static_cast<int>(m_image->size().area() * sizeof(ImageFrame: :PixelData)); |
308 EXPECT_EQ(frameSize, m_imageObserver->m_lastDecodedSizeChangedDelta); | 384 EXPECT_EQ(frameSize, lastDecodedSizeChange()); |
309 frameAtIndex(0); | |
310 | |
311 // Trying to destroy all data except an undecoded frame should go ahead and | |
312 // destroy all other frames. | |
313 setCurrentFrame(2); | |
314 destroyDecodedData(false); | |
315 EXPECT_EQ(-frameSize * 2, m_imageObserver->m_lastDecodedSizeChangedDelta); | |
316 } | 385 } |
317 | 386 |
318 template <typename HistogramEnumType> | 387 template <typename HistogramEnumType> |
319 struct HistogramTestParams { | 388 struct HistogramTestParams { |
320 const char* filename; | 389 const char* filename; |
321 HistogramEnumType type; | 390 HistogramEnumType type; |
322 }; | 391 }; |
323 | 392 |
324 template <typename HistogramEnumType> | 393 template <typename HistogramEnumType> |
325 class BitmapHistogramTest | 394 class BitmapHistogramTest |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
368 {"/LayoutTests/fast/images/resources/exif-orientation-5-lu.jpg", OriginLeftT op}, | 437 {"/LayoutTests/fast/images/resources/exif-orientation-5-lu.jpg", OriginLeftT op}, |
369 {"/LayoutTests/fast/images/resources/exif-orientation-6-ru.jpg", OriginRight Top}, | 438 {"/LayoutTests/fast/images/resources/exif-orientation-6-ru.jpg", OriginRight Top}, |
370 {"/LayoutTests/fast/images/resources/exif-orientation-7-rl.jpg", OriginRight Bottom}, | 439 {"/LayoutTests/fast/images/resources/exif-orientation-7-rl.jpg", OriginRight Bottom}, |
371 {"/LayoutTests/fast/images/resources/exif-orientation-8-llo.jpg", OriginLeft Bottom} | 440 {"/LayoutTests/fast/images/resources/exif-orientation-8-llo.jpg", OriginLeft Bottom} |
372 }; | 441 }; |
373 | 442 |
374 INSTANTIATE_TEST_CASE_P(DecodedImageOrientationHistogramTest, DecodedImageOrient ationHistogramTest, | 443 INSTANTIATE_TEST_CASE_P(DecodedImageOrientationHistogramTest, DecodedImageOrient ationHistogramTest, |
375 ::testing::ValuesIn(kDecodedImageOrientationHistogramTestParams)); | 444 ::testing::ValuesIn(kDecodedImageOrientationHistogramTestParams)); |
376 | 445 |
377 } // namespace blink | 446 } // namespace blink |
OLD | NEW |