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 "third_party/blink/renderer/platform/graphics/image_decoding_store.h"
27
28 #include <memory>
29 #include "base/memory/memory_pressure_listener.h"
30 #include "base/run_loop.h"
31 #include "testing/gtest/include/gtest/gtest.h"
32 #include "third_party/blink/renderer/platform/graphics/image_frame_generator.h"
33 #include "third_party/blink/renderer/platform/graphics/test/mock_image_decoder.h"
34
35 namespace blink {
36
37 class ImageDecodingStoreTest : public testing::Test,
38 public MockImageDecoderClient {
39 public:
SetUp()40 void SetUp() override {
41 ImageDecodingStore::Instance().SetCacheLimitInBytes(1024 * 1024);
42 generator_ = ImageFrameGenerator::Create(SkISize::Make(100, 100), true,
43 ColorBehavior::Ignore(), {});
44 decoders_destroyed_ = 0;
45 }
46
TearDown()47 void TearDown() override { ImageDecodingStore::Instance().Clear(); }
48
DecoderBeingDestroyed()49 void DecoderBeingDestroyed() override { ++decoders_destroyed_; }
50
DecodeRequested()51 void DecodeRequested() override {
52 // Decoder is never used by ImageDecodingStore.
53 ASSERT_TRUE(false);
54 }
55
GetStatus(size_t index)56 ImageFrame::Status GetStatus(size_t index) override {
57 return ImageFrame::kFramePartial;
58 }
59
FrameCount()60 size_t FrameCount() override { return 1; }
RepetitionCount() const61 int RepetitionCount() const override { return kAnimationNone; }
FrameDuration() const62 base::TimeDelta FrameDuration() const override { return base::TimeDelta(); }
63
64 protected:
EvictOneCache()65 void EvictOneCache() {
66 size_t memory_usage_in_bytes =
67 ImageDecodingStore::Instance().MemoryUsageInBytes();
68 if (memory_usage_in_bytes)
69 ImageDecodingStore::Instance().SetCacheLimitInBytes(
70 memory_usage_in_bytes - 1);
71 else
72 ImageDecodingStore::Instance().SetCacheLimitInBytes(0);
73 }
74
75 scoped_refptr<ImageFrameGenerator> generator_;
76 int decoders_destroyed_;
77 };
78
TEST_F(ImageDecodingStoreTest,insertDecoder)79 TEST_F(ImageDecodingStoreTest, insertDecoder) {
80 const SkISize size = SkISize::Make(1, 1);
81 auto decoder = std::make_unique<MockImageDecoder>(this);
82 decoder->SetSize(1, 1);
83 const ImageDecoder* ref_decoder = decoder.get();
84 ImageDecodingStore::Instance().InsertDecoder(
85 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
86 std::move(decoder));
87 EXPECT_EQ(1, ImageDecodingStore::Instance().CacheEntries());
88 EXPECT_EQ(4u, ImageDecodingStore::Instance().MemoryUsageInBytes());
89
90 ImageDecoder* test_decoder;
91 EXPECT_TRUE(ImageDecodingStore::Instance().LockDecoder(
92 generator_.get(), size, ImageDecoder::kAlphaPremultiplied,
93 cc::PaintImage::kDefaultGeneratorClientId, &test_decoder));
94 EXPECT_TRUE(test_decoder);
95 EXPECT_EQ(ref_decoder, test_decoder);
96 ImageDecodingStore::Instance().UnlockDecoder(
97 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
98 test_decoder);
99 EXPECT_EQ(1, ImageDecodingStore::Instance().CacheEntries());
100 }
101
TEST_F(ImageDecodingStoreTest,evictDecoder)102 TEST_F(ImageDecodingStoreTest, evictDecoder) {
103 auto decoder1 = std::make_unique<MockImageDecoder>(this);
104 auto decoder2 = std::make_unique<MockImageDecoder>(this);
105 auto decoder3 = std::make_unique<MockImageDecoder>(this);
106 decoder1->SetSize(1, 1);
107 decoder2->SetSize(2, 2);
108 decoder3->SetSize(3, 3);
109 ImageDecodingStore::Instance().InsertDecoder(
110 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
111 std::move(decoder1));
112 ImageDecodingStore::Instance().InsertDecoder(
113 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
114 std::move(decoder2));
115 ImageDecodingStore::Instance().InsertDecoder(
116 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
117 std::move(decoder3));
118 EXPECT_EQ(3, ImageDecodingStore::Instance().CacheEntries());
119 EXPECT_EQ(56u, ImageDecodingStore::Instance().MemoryUsageInBytes());
120
121 EvictOneCache();
122 EXPECT_EQ(2, ImageDecodingStore::Instance().CacheEntries());
123 EXPECT_EQ(52u, ImageDecodingStore::Instance().MemoryUsageInBytes());
124
125 EvictOneCache();
126 EXPECT_EQ(1, ImageDecodingStore::Instance().CacheEntries());
127 EXPECT_EQ(36u, ImageDecodingStore::Instance().MemoryUsageInBytes());
128
129 EvictOneCache();
130 EXPECT_FALSE(ImageDecodingStore::Instance().CacheEntries());
131 EXPECT_FALSE(ImageDecodingStore::Instance().MemoryUsageInBytes());
132 }
133
TEST_F(ImageDecodingStoreTest,decoderInUseNotEvicted)134 TEST_F(ImageDecodingStoreTest, decoderInUseNotEvicted) {
135 auto decoder1 = std::make_unique<MockImageDecoder>(this);
136 auto decoder2 = std::make_unique<MockImageDecoder>(this);
137 auto decoder3 = std::make_unique<MockImageDecoder>(this);
138 decoder1->SetSize(1, 1);
139 decoder2->SetSize(2, 2);
140 decoder3->SetSize(3, 3);
141 ImageDecodingStore::Instance().InsertDecoder(
142 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
143 std::move(decoder1));
144 ImageDecodingStore::Instance().InsertDecoder(
145 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
146 std::move(decoder2));
147 ImageDecodingStore::Instance().InsertDecoder(
148 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
149 std::move(decoder3));
150 EXPECT_EQ(3, ImageDecodingStore::Instance().CacheEntries());
151
152 ImageDecoder* test_decoder;
153 EXPECT_TRUE(ImageDecodingStore::Instance().LockDecoder(
154 generator_.get(), SkISize::Make(2, 2), ImageDecoder::kAlphaPremultiplied,
155 cc::PaintImage::kDefaultGeneratorClientId, &test_decoder));
156
157 EvictOneCache();
158 EvictOneCache();
159 EvictOneCache();
160 EXPECT_EQ(1, ImageDecodingStore::Instance().CacheEntries());
161 EXPECT_EQ(16u, ImageDecodingStore::Instance().MemoryUsageInBytes());
162
163 ImageDecodingStore::Instance().UnlockDecoder(
164 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
165 test_decoder);
166 EvictOneCache();
167 EXPECT_FALSE(ImageDecodingStore::Instance().CacheEntries());
168 EXPECT_FALSE(ImageDecodingStore::Instance().MemoryUsageInBytes());
169 }
170
TEST_F(ImageDecodingStoreTest,removeDecoder)171 TEST_F(ImageDecodingStoreTest, removeDecoder) {
172 const SkISize size = SkISize::Make(1, 1);
173 auto decoder = std::make_unique<MockImageDecoder>(this);
174 decoder->SetSize(1, 1);
175 const ImageDecoder* ref_decoder = decoder.get();
176 ImageDecodingStore::Instance().InsertDecoder(
177 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
178 std::move(decoder));
179 EXPECT_EQ(1, ImageDecodingStore::Instance().CacheEntries());
180 EXPECT_EQ(4u, ImageDecodingStore::Instance().MemoryUsageInBytes());
181
182 ImageDecoder* test_decoder;
183 EXPECT_TRUE(ImageDecodingStore::Instance().LockDecoder(
184 generator_.get(), size, ImageDecoder::kAlphaPremultiplied,
185 cc::PaintImage::kDefaultGeneratorClientId, &test_decoder));
186 EXPECT_TRUE(test_decoder);
187 EXPECT_EQ(ref_decoder, test_decoder);
188 ImageDecodingStore::Instance().RemoveDecoder(
189 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
190 test_decoder);
191 EXPECT_FALSE(ImageDecodingStore::Instance().CacheEntries());
192
193 EXPECT_FALSE(ImageDecodingStore::Instance().LockDecoder(
194 generator_.get(), size, ImageDecoder::kAlphaPremultiplied,
195 cc::PaintImage::kDefaultGeneratorClientId, &test_decoder));
196 }
197
TEST_F(ImageDecodingStoreTest,MultipleClientsForSameGenerator)198 TEST_F(ImageDecodingStoreTest, MultipleClientsForSameGenerator) {
199 ImageDecodingStore::Instance().Clear();
200 ASSERT_EQ(ImageDecodingStore::Instance().CacheEntries(), 0);
201
202 const SkISize size = SkISize::Make(1, 1);
203
204 auto decoder = std::make_unique<MockImageDecoder>(this);
205 ImageDecoder* decoder_1 = decoder.get();
206 decoder_1->SetSize(1, 1);
207 auto client_id_1 = cc::PaintImage::GetNextGeneratorClientId();
208 ImageDecodingStore::Instance().InsertDecoder(generator_.get(), client_id_1,
209 std::move(decoder));
210 EXPECT_EQ(ImageDecodingStore::Instance().CacheEntries(), 1);
211
212 decoder = std::make_unique<MockImageDecoder>(this);
213 ImageDecoder* decoder_2 = decoder.get();
214 decoder_2->SetSize(1, 1);
215 auto client_id_2 = cc::PaintImage::GetNextGeneratorClientId();
216 ImageDecodingStore::Instance().InsertDecoder(generator_.get(), client_id_2,
217 std::move(decoder));
218 EXPECT_EQ(ImageDecodingStore::Instance().CacheEntries(), 2);
219
220 ImageDecoder* cached_decoder = nullptr;
221 ImageDecodingStore::Instance().LockDecoder(generator_.get(), size,
222 ImageDecoder::kAlphaPremultiplied,
223 client_id_1, &cached_decoder);
224 EXPECT_EQ(decoder_1, cached_decoder);
225
226 ImageDecodingStore::Instance().LockDecoder(generator_.get(), size,
227 ImageDecoder::kAlphaPremultiplied,
228 client_id_2, &cached_decoder);
229 EXPECT_EQ(decoder_2, cached_decoder);
230
231 ImageDecodingStore::Instance().RemoveDecoder(generator_.get(), client_id_1,
232 decoder_1);
233 ImageDecodingStore::Instance().RemoveDecoder(generator_.get(), client_id_2,
234 decoder_2);
235 EXPECT_EQ(ImageDecodingStore::Instance().CacheEntries(), 0);
236 }
237
TEST_F(ImageDecodingStoreTest,OnMemoryPressure)238 TEST_F(ImageDecodingStoreTest, OnMemoryPressure) {
239 auto decoder = std::make_unique<MockImageDecoder>(this);
240 decoder->SetSize(1, 1);
241 ImageDecodingStore::Instance().InsertDecoder(
242 generator_.get(), cc::PaintImage::kDefaultGeneratorClientId,
243 std::move(decoder));
244 EXPECT_EQ(1, ImageDecodingStore::Instance().CacheEntries());
245 EXPECT_EQ(4u, ImageDecodingStore::Instance().MemoryUsageInBytes());
246
247 base::MemoryPressureListener::SimulatePressureNotification(
248 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE);
249 base::RunLoop().RunUntilIdle();
250
251 EXPECT_EQ(1, ImageDecodingStore::Instance().CacheEntries());
252 EXPECT_EQ(4u, ImageDecodingStore::Instance().MemoryUsageInBytes());
253
254 base::MemoryPressureListener::SimulatePressureNotification(
255 base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
256 base::RunLoop().RunUntilIdle();
257
258 EXPECT_EQ(0, ImageDecodingStore::Instance().CacheEntries());
259 EXPECT_EQ(0u, ImageDecodingStore::Instance().MemoryUsageInBytes());
260 }
261
262 } // namespace blink
263