1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "cc/tiles/software_image_decode_cache.h"
6 
7 #include "base/strings/stringprintf.h"
8 #include "cc/paint/draw_image.h"
9 #include "cc/paint/paint_image_builder.h"
10 #include "cc/test/fake_paint_image_generator.h"
11 #include "cc/test/skia_common.h"
12 #include "cc/test/test_tile_task_runner.h"
13 #include "testing/gtest/include/gtest/gtest.h"
14 #include "third_party/skia/include/core/SkRefCnt.h"
15 
16 namespace cc {
17 namespace {
18 
19 size_t kLockedMemoryLimitBytes = 128 * 1024 * 1024;
CreateMatrix(const SkSize & scale,bool is_decomposable)20 SkMatrix CreateMatrix(const SkSize& scale, bool is_decomposable) {
21   SkMatrix matrix;
22   matrix.setScale(scale.width(), scale.height());
23 
24   if (!is_decomposable) {
25     // Perspective is not decomposable, add it.
26     matrix[SkMatrix::kMPersp0] = 0.1f;
27   }
28 
29   return matrix;
30 }
31 
32 class BaseTest : public testing::Test {
33  public:
SetUp()34   void SetUp() override {
35     cache_ = CreateCache();
36     paint_image_ = CreatePaintImage(gfx::Size(512, 512));
37   }
38 
TearDown()39   void TearDown() override {
40     paint_image_ = PaintImage();
41     cache_.reset();
42   }
43 
CreateDrawImageForScale(float scale,const SkIRect src_rect=SkIRect::MakeEmpty ())44   DrawImage CreateDrawImageForScale(
45       float scale,
46       const SkIRect src_rect = SkIRect::MakeEmpty()) {
47     return DrawImage(
48         paint_image(),
49         src_rect.isEmpty()
50             ? SkIRect::MakeWH(paint_image().width(), paint_image().height())
51             : src_rect,
52         kMedium_SkFilterQuality, CreateMatrix(SkSize::Make(scale, scale), true),
53         PaintImage::kDefaultFrameIndex, GetColorSpace());
54   }
55 
cache()56   SoftwareImageDecodeCache& cache() { return *cache_; }
paint_image()57   PaintImage& paint_image() { return paint_image_; }
58 
59  protected:
60   struct CacheEntryResult {
61     bool has_task = false;
62     bool needs_unref = false;
63   };
64 
65   virtual std::unique_ptr<SoftwareImageDecodeCache> CreateCache() = 0;
66   virtual CacheEntryResult GenerateCacheEntry(const DrawImage& image) = 0;
67   virtual PaintImage CreatePaintImage(const gfx::Size& size) = 0;
68   virtual gfx::ColorSpace GetColorSpace() = 0;
69   virtual void VerifyEntryExists(int line,
70                                  const DrawImage& draw_image,
71                                  const gfx::Size& expected_size) = 0;
72 
73  private:
74   std::unique_ptr<SoftwareImageDecodeCache> cache_;
75   PaintImage paint_image_;
76 };
77 
78 class N32Cache : public virtual BaseTest {
79  protected:
CreateCache()80   std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
81     return std::make_unique<SoftwareImageDecodeCache>(
82         kN32_SkColorType, kLockedMemoryLimitBytes,
83         PaintImage::kDefaultGeneratorClientId);
84   }
85 };
86 
87 class RGBA4444Cache : public virtual BaseTest {
88  protected:
CreateCache()89   std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
90     return std::make_unique<SoftwareImageDecodeCache>(
91         kARGB_4444_SkColorType, kLockedMemoryLimitBytes,
92         PaintImage::kDefaultGeneratorClientId);
93   }
94 };
95 
96 class RGBA_F16Cache : public virtual BaseTest {
97  protected:
CreateCache()98   std::unique_ptr<SoftwareImageDecodeCache> CreateCache() override {
99     return std::make_unique<SoftwareImageDecodeCache>(
100         kRGBA_F16_SkColorType, kLockedMemoryLimitBytes,
101         PaintImage::kDefaultGeneratorClientId);
102   }
103 };
104 
105 class AtRaster : public virtual BaseTest {
106  protected:
GenerateCacheEntry(const DrawImage & image)107   CacheEntryResult GenerateCacheEntry(const DrawImage& image) override {
108     // At raster doesn't generate cache entries.
109     return {false, false};
110   }
VerifyEntryExists(int line,const DrawImage & draw_image,const gfx::Size & expected_size)111   void VerifyEntryExists(int line,
112                          const DrawImage& draw_image,
113                          const gfx::Size& expected_size) override {
114     auto decoded = cache().GetDecodedImageForDraw(draw_image);
115     SCOPED_TRACE(base::StringPrintf("Failure from line %d", line));
116     EXPECT_EQ(decoded.image()->width(), expected_size.width());
117     EXPECT_EQ(decoded.image()->height(), expected_size.height());
118     cache().DrawWithImageFinished(draw_image, decoded);
119   }
120 };
121 
122 class Predecode : public virtual BaseTest {
123  protected:
GenerateCacheEntry(const DrawImage & image)124   CacheEntryResult GenerateCacheEntry(const DrawImage& image) override {
125     auto task_result =
126         cache().GetTaskForImageAndRef(image, ImageDecodeCache::TracingInfo());
127     CacheEntryResult result = {!!task_result.task, task_result.need_unref};
128 
129     if (task_result.task)
130       TestTileTaskRunner::ProcessTask(task_result.task.get());
131     return result;
132   }
133 
VerifyEntryExists(int line,const DrawImage & draw_image,const gfx::Size & expected_size)134   void VerifyEntryExists(int line,
135                          const DrawImage& draw_image,
136                          const gfx::Size& expected_size) override {
137     auto decoded = cache().GetDecodedImageForDraw(draw_image);
138     EXPECT_TRUE(SkColorSpace::Equals(
139         decoded.image()->colorSpace(),
140         draw_image.target_color_space().ToSkColorSpace().get()));
141     SCOPED_TRACE(base::StringPrintf("Failure from line %d", line));
142     EXPECT_EQ(decoded.image()->width(), expected_size.width());
143     EXPECT_EQ(decoded.image()->height(), expected_size.height());
144     cache().DrawWithImageFinished(draw_image, decoded);
145   }
146 };
147 
148 class NoDecodeToScaleSupport : public virtual BaseTest {
149  protected:
CreatePaintImage(const gfx::Size & size)150   PaintImage CreatePaintImage(const gfx::Size& size) override {
151     return CreateDiscardablePaintImage(size, GetColorSpace().ToSkColorSpace());
152   }
153 };
154 
155 class NoDecodeToScaleSupportF16 : public virtual BaseTest {
156  protected:
CreatePaintImage(const gfx::Size & size)157   PaintImage CreatePaintImage(const gfx::Size& size) override {
158     PaintImage paint_image = CreateDiscardablePaintImage(
159         size, GetColorSpace().ToSkColorSpace(),
160         true /*allocate_encoded_memory*/, PaintImage::kInvalidId,
161         kRGBA_F16_SkColorType);
162     return paint_image;
163   }
164 };
165 
166 class DefaultColorSpace : public virtual BaseTest {
167  protected:
GetColorSpace()168   gfx::ColorSpace GetColorSpace() override {
169     return gfx::ColorSpace::CreateSRGB();
170   }
171 };
172 
173 class ExoticColorSpace : public virtual BaseTest {
174  protected:
GetColorSpace()175   gfx::ColorSpace GetColorSpace() override {
176     return gfx::ColorSpace(gfx::ColorSpace::PrimaryID::XYZ_D50,
177                            gfx::ColorSpace::TransferID::IEC61966_2_1);
178   }
179 };
180 
181 class WideGamutCanvasColorSpace : public virtual BaseTest {
182  protected:
GetColorSpace()183   gfx::ColorSpace GetColorSpace() override {
184     return gfx::ColorSpace(gfx::ColorSpace::PrimaryID::SMPTEST432_1,  // P3
185                            gfx::ColorSpace::TransferID::LINEAR);
186   }
187 };
188 class SoftwareImageDecodeCacheTest_Typical : public N32Cache,
189                                              public Predecode,
190                                              public NoDecodeToScaleSupport,
191                                              public DefaultColorSpace {};
192 
TEST_F(SoftwareImageDecodeCacheTest_Typical,UseClosestAvailableDecode)193 TEST_F(SoftwareImageDecodeCacheTest_Typical, UseClosestAvailableDecode) {
194   auto draw_image_50 = CreateDrawImageForScale(0.5f);
195   auto result = GenerateCacheEntry(draw_image_50);
196   EXPECT_TRUE(result.has_task);
197   EXPECT_TRUE(result.needs_unref);
198 
199   // Clear the cache to eliminate the transient 1.f scale from the cache.
200   cache().ClearCache();
201   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(256, 256));
202   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
203 
204   auto draw_image_125 = CreateDrawImageForScale(0.125f);
205   result = GenerateCacheEntry(draw_image_125);
206   EXPECT_TRUE(result.has_task);
207   EXPECT_TRUE(result.needs_unref);
208   VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(64, 64));
209 
210   // We didn't clear the cache the second time, and should only expect to find
211   // these entries: 0.5 scale and 0.125 scale.
212   EXPECT_EQ(2u, cache().GetNumCacheEntriesForTesting());
213 
214   cache().UnrefImage(draw_image_50);
215   cache().UnrefImage(draw_image_125);
216 }
217 
TEST_F(SoftwareImageDecodeCacheTest_Typical,UseClosestAvailableDecodeNotSmaller)218 TEST_F(SoftwareImageDecodeCacheTest_Typical,
219        UseClosestAvailableDecodeNotSmaller) {
220   auto draw_image_25 = CreateDrawImageForScale(0.25f);
221   auto result = GenerateCacheEntry(draw_image_25);
222   EXPECT_TRUE(result.has_task);
223   EXPECT_TRUE(result.needs_unref);
224 
225   // Clear the cache to eliminate the transient 1.f scale from the cache.
226   cache().ClearCache();
227   VerifyEntryExists(__LINE__, draw_image_25, gfx::Size(128, 128));
228   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
229 
230   auto draw_image_50 = CreateDrawImageForScale(0.5f);
231   result = GenerateCacheEntry(draw_image_50);
232   EXPECT_TRUE(result.has_task);
233   EXPECT_TRUE(result.needs_unref);
234   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(256, 256));
235 
236   // We didn't clear the cache the second time, and should only expect to find
237   // these entries: 1.0 scale, 0.5 scale and 0.25 scale.
238   EXPECT_EQ(3u, cache().GetNumCacheEntriesForTesting());
239 
240   cache().UnrefImage(draw_image_50);
241   cache().UnrefImage(draw_image_25);
242 }
243 
TEST_F(SoftwareImageDecodeCacheTest_Typical,UseClosestAvailableDecodeFirstImageSubrected)244 TEST_F(SoftwareImageDecodeCacheTest_Typical,
245        UseClosestAvailableDecodeFirstImageSubrected) {
246   auto draw_image_50 = CreateDrawImageForScale(0.5f, SkIRect::MakeWH(500, 500));
247   auto result = GenerateCacheEntry(draw_image_50);
248   EXPECT_TRUE(result.has_task);
249   EXPECT_TRUE(result.needs_unref);
250 
251   // Clear the cache to eliminate the transient 1.f scale from the cache.
252   cache().ClearCache();
253   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(250, 250));
254   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
255 
256   auto draw_image_125 = CreateDrawImageForScale(0.125f);
257   result = GenerateCacheEntry(draw_image_125);
258   EXPECT_TRUE(result.has_task);
259   EXPECT_TRUE(result.needs_unref);
260   VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(64, 64));
261 
262   // We didn't clear the cache the second time, and should only expect to find
263   // these entries: 1.0 scale, 0.5 scale subrected and 0.125 scale.
264   EXPECT_EQ(3u, cache().GetNumCacheEntriesForTesting());
265 
266   cache().UnrefImage(draw_image_50);
267   cache().UnrefImage(draw_image_125);
268 }
269 
TEST_F(SoftwareImageDecodeCacheTest_Typical,UseClosestAvailableDecodeSecondImageSubrected)270 TEST_F(SoftwareImageDecodeCacheTest_Typical,
271        UseClosestAvailableDecodeSecondImageSubrected) {
272   auto draw_image_50 = CreateDrawImageForScale(0.5f);
273   auto result = GenerateCacheEntry(draw_image_50);
274   EXPECT_TRUE(result.has_task);
275   EXPECT_TRUE(result.needs_unref);
276 
277   // Clear the cache to eliminate the transient 1.f scale from the cache.
278   cache().ClearCache();
279   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(256, 256));
280   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
281 
282   auto draw_image_125 =
283       CreateDrawImageForScale(0.125f, SkIRect::MakeWH(400, 400));
284   result = GenerateCacheEntry(draw_image_125);
285   EXPECT_TRUE(result.has_task);
286   EXPECT_TRUE(result.needs_unref);
287   VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(50, 50));
288 
289   // We didn't clear the cache the second time, and should only expect to find
290   // these entries: 1.0 scale, 0.5 scale and 0.125 scale subrected.
291   EXPECT_EQ(3u, cache().GetNumCacheEntriesForTesting());
292 
293   cache().UnrefImage(draw_image_50);
294   cache().UnrefImage(draw_image_125);
295 }
296 
TEST_F(SoftwareImageDecodeCacheTest_Typical,UseClosestAvailableDecodeBothSubrected)297 TEST_F(SoftwareImageDecodeCacheTest_Typical,
298        UseClosestAvailableDecodeBothSubrected) {
299   auto draw_image_50 = CreateDrawImageForScale(0.5f, SkIRect::MakeWH(400, 400));
300   auto result = GenerateCacheEntry(draw_image_50);
301   EXPECT_TRUE(result.has_task);
302   EXPECT_TRUE(result.needs_unref);
303 
304   // Clear the cache to eliminate the transient 1.f scale from the cache.
305   cache().ClearCache();
306   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(200, 200));
307   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
308 
309   auto draw_image_125 =
310       CreateDrawImageForScale(0.125f, SkIRect::MakeWH(400, 400));
311   result = GenerateCacheEntry(draw_image_125);
312   EXPECT_TRUE(result.has_task);
313   EXPECT_TRUE(result.needs_unref);
314   VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(50, 50));
315 
316   // We didn't clear the cache the second time, and should only expect to find
317   // these entries: 0.5 scale subrected and 0.125 scale subrected.
318   EXPECT_EQ(2u, cache().GetNumCacheEntriesForTesting());
319 
320   cache().UnrefImage(draw_image_50);
321   cache().UnrefImage(draw_image_125);
322 }
323 
TEST_F(SoftwareImageDecodeCacheTest_Typical,UseClosestAvailableDecodeBothPastPostScaleSize)324 TEST_F(SoftwareImageDecodeCacheTest_Typical,
325        UseClosestAvailableDecodeBothPastPostScaleSize) {
326   auto draw_image_50 =
327       CreateDrawImageForScale(0.5f, SkIRect::MakeXYWH(300, 300, 52, 52));
328   auto result = GenerateCacheEntry(draw_image_50);
329   EXPECT_TRUE(result.has_task);
330   EXPECT_TRUE(result.needs_unref);
331 
332   // Clear the cache to eliminate the transient 1.f scale from the cache.
333   cache().ClearCache();
334   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(26, 26));
335   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
336 
337   auto draw_image_25 =
338       CreateDrawImageForScale(0.25, SkIRect::MakeXYWH(300, 300, 52, 52));
339   result = GenerateCacheEntry(draw_image_25);
340   EXPECT_TRUE(result.has_task);
341   EXPECT_TRUE(result.needs_unref);
342   VerifyEntryExists(__LINE__, draw_image_25, gfx::Size(13, 13));
343 
344   // We didn't clear the cache the second time, and should only expect to find
345   // these entries: 0.5 scale subrected and 0.25 scale subrected.
346   EXPECT_EQ(2u, cache().GetNumCacheEntriesForTesting());
347 
348   cache().UnrefImage(draw_image_50);
349   cache().UnrefImage(draw_image_25);
350 }
351 
352 class SoftwareImageDecodeCacheTest_AtRaster : public N32Cache,
353                                               public AtRaster,
354                                               public NoDecodeToScaleSupport,
355                                               public DefaultColorSpace {};
356 
TEST_F(SoftwareImageDecodeCacheTest_AtRaster,UseClosestAvailableDecode)357 TEST_F(SoftwareImageDecodeCacheTest_AtRaster, UseClosestAvailableDecode) {
358   auto draw_image_50 = CreateDrawImageForScale(0.5f);
359   auto decoded = cache().GetDecodedImageForDraw(draw_image_50);
360   {
361     VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(256, 256));
362     cache().ClearCache();
363     EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
364 
365     auto draw_image_125 = CreateDrawImageForScale(0.125f);
366     VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(64, 64));
367   }
368   cache().DrawWithImageFinished(draw_image_50, decoded);
369 
370   // We should only expect to find these entries: 0.5 scale and 0.125 scale.
371   EXPECT_EQ(2u, cache().GetNumCacheEntriesForTesting());
372 }
373 
TEST_F(SoftwareImageDecodeCacheTest_AtRaster,UseClosestAvailableDecodeSubrected)374 TEST_F(SoftwareImageDecodeCacheTest_AtRaster,
375        UseClosestAvailableDecodeSubrected) {
376   auto draw_image_50 = CreateDrawImageForScale(0.5f, SkIRect::MakeWH(500, 500));
377   auto decoded = cache().GetDecodedImageForDraw(draw_image_50);
378   {
379     VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(250, 250));
380     cache().ClearCache();
381     EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
382 
383     auto draw_image_125 = CreateDrawImageForScale(0.125f);
384     VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(64, 64));
385   }
386   cache().DrawWithImageFinished(draw_image_50, decoded);
387 
388   // We should only expect to find these entries: 1.0 scale, 0.5 scale subrected
389   // and 0.125 scale.
390   EXPECT_EQ(3u, cache().GetNumCacheEntriesForTesting());
391 }
392 
393 class SoftwareImageDecodeCacheTest_ExoticColorSpace
394     : public N32Cache,
395       public Predecode,
396       public NoDecodeToScaleSupport,
397       public ExoticColorSpace {};
398 
TEST_F(SoftwareImageDecodeCacheTest_ExoticColorSpace,UseClosestAvailableDecode)399 TEST_F(SoftwareImageDecodeCacheTest_ExoticColorSpace,
400        UseClosestAvailableDecode) {
401   auto draw_image_50 = CreateDrawImageForScale(0.5f);
402   auto result = GenerateCacheEntry(draw_image_50);
403 
404   EXPECT_TRUE(result.has_task);
405   EXPECT_TRUE(result.needs_unref);
406 
407   // Clear the cache to eliminate the transient 1.f scale from the cache.
408   cache().ClearCache();
409   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(256, 256));
410   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
411 
412   auto draw_image_125 = CreateDrawImageForScale(0.125f);
413   result = GenerateCacheEntry(draw_image_125);
414   EXPECT_TRUE(result.has_task);
415   EXPECT_TRUE(result.needs_unref);
416   VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(64, 64));
417 
418   // We didn't clear the cache the second time, and should only expect to find
419   // these entries: 0.5 scale and 0.125 scale.
420   EXPECT_EQ(2u, cache().GetNumCacheEntriesForTesting());
421 
422   cache().UnrefImage(draw_image_50);
423   cache().UnrefImage(draw_image_125);
424 }
425 
426 class SoftwareImageDecodeCacheTest_F16_ExoticColorSpace
427     : public RGBA_F16Cache,
428       public Predecode,
429       public NoDecodeToScaleSupportF16,
430       public ExoticColorSpace {};
431 
TEST_F(SoftwareImageDecodeCacheTest_F16_ExoticColorSpace,UseClosestAvailableDecode_F16_ExoticColorSpace)432 TEST_F(SoftwareImageDecodeCacheTest_F16_ExoticColorSpace,
433        UseClosestAvailableDecode_F16_ExoticColorSpace) {
434   auto draw_image_50 = CreateDrawImageForScale(0.5f);
435   auto result = GenerateCacheEntry(draw_image_50);
436   EXPECT_TRUE(result.has_task);
437   EXPECT_TRUE(result.needs_unref);
438 
439   // Clear the cache to eliminate the transient 1.f scale from the cache.
440   cache().ClearCache();
441   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(256, 256));
442   EXPECT_EQ(kRGBA_F16_SkColorType, draw_image_50.paint_image().GetColorType());
443   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
444 
445   auto draw_image_125 = CreateDrawImageForScale(0.125f);
446   result = GenerateCacheEntry(draw_image_125);
447   EXPECT_TRUE(result.has_task);
448   EXPECT_TRUE(result.needs_unref);
449   VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(64, 64));
450   EXPECT_EQ(kRGBA_F16_SkColorType, draw_image_125.paint_image().GetColorType());
451 
452   // We didn't clear the cache the second time, and should only expect to find
453   // these entries: 0.5 scale and 0.125 scale.
454   EXPECT_EQ(2u, cache().GetNumCacheEntriesForTesting());
455 
456   cache().UnrefImage(draw_image_50);
457   cache().UnrefImage(draw_image_125);
458 }
459 
460 class SoftwareImageDecodeCacheTest_F16_WideGamutCanvasColorSpace
461     : public RGBA_F16Cache,
462       public Predecode,
463       public NoDecodeToScaleSupportF16,
464       public WideGamutCanvasColorSpace {};
465 
TEST_F(SoftwareImageDecodeCacheTest_F16_WideGamutCanvasColorSpace,UseClosestAvailableDecode_F16_WideGamutCanvasColorSpace)466 TEST_F(SoftwareImageDecodeCacheTest_F16_WideGamutCanvasColorSpace,
467        UseClosestAvailableDecode_F16_WideGamutCanvasColorSpace) {
468   auto draw_image_50 = CreateDrawImageForScale(0.5f);
469   auto result = GenerateCacheEntry(draw_image_50);
470   EXPECT_TRUE(result.has_task);
471   EXPECT_TRUE(result.needs_unref);
472 
473   // Clear the cache to eliminate the transient 1.f scale from the cache.
474   cache().ClearCache();
475   VerifyEntryExists(__LINE__, draw_image_50, gfx::Size(256, 256));
476   EXPECT_EQ(kRGBA_F16_SkColorType, draw_image_50.paint_image().GetColorType());
477   EXPECT_EQ(1u, cache().GetNumCacheEntriesForTesting());
478 
479   auto draw_image_125 = CreateDrawImageForScale(0.125f);
480   result = GenerateCacheEntry(draw_image_125);
481   EXPECT_TRUE(result.has_task);
482   EXPECT_TRUE(result.needs_unref);
483   VerifyEntryExists(__LINE__, draw_image_125, gfx::Size(64, 64));
484   EXPECT_EQ(kRGBA_F16_SkColorType, draw_image_125.paint_image().GetColorType());
485 
486   // We didn't clear the cache the second time, and should only expect to find
487   // these entries: 0.5 scale and 0.125 scale.
488   EXPECT_EQ(2u, cache().GetNumCacheEntriesForTesting());
489 
490   cache().UnrefImage(draw_image_50);
491   cache().UnrefImage(draw_image_125);
492 }
493 
494 }  // namespace
495 }  // namespace cc
496