[M108 Migration][VD] Avoid pending frame counter becoming negative
[platform/framework/web/chromium-efl.git] / cc / tiles / checker_image_tracker_unittest.cc
1 // Copyright 2017 The Chromium Authors
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/checker_image_tracker.h"
6
7 #include <memory>
8 #include <unordered_set>
9 #include <utility>
10
11 #include "base/bind.h"
12 #include "base/run_loop.h"
13 #include "base/threading/thread_task_runner_handle.h"
14 #include "cc/paint/paint_image_builder.h"
15 #include "cc/test/skia_common.h"
16 #include "cc/tiles/image_controller.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18
19 namespace cc {
20 namespace {
21
22 // 5MB max image cache size.
23 const size_t kMaxImageCacheSizeBytes = 5 * 1024 * 1024;
24
25 const int kCheckerableImageDimension = 512;
26 // This size will result in an image just over kMaxImageCacheSizeBytes.
27 const int kLargeNonCheckerableImageDimension = 1145;
28 const int kSmallNonCheckerableImageDimension = 16;
29
30 const TargetColorParams kDefaultTargetColorParams;
31
32 class TestImageController : public ImageController {
33  public:
34   // We can use the same thread for the image worker because all use of it in
35   // the ImageController is over-ridden here.
36   TestImageController()
37       : ImageController(base::ThreadTaskRunnerHandle::Get().get(),
38                         base::ThreadTaskRunnerHandle::Get()) {
39     SetMaxImageCacheLimitBytesForTesting(kMaxImageCacheSizeBytes);
40   }
41
42   ~TestImageController() override { DCHECK_EQ(locked_images_.size(), 0U); }
43
44   int num_of_locked_images() const { return locked_images_.size(); }
45   const PaintImageIdFlatSet& decodes_requested() const {
46     return decodes_requested_;
47   }
48   const std::vector<DrawImage>& decoded_images() const {
49     return decoded_images_;
50   }
51
52   void UnlockImageDecode(ImageDecodeRequestId id) override {
53     DCHECK_EQ(locked_images_.count(id), 1U);
54     locked_images_.erase(id);
55   }
56
57   ImageDecodeRequestId QueueImageDecode(
58       const DrawImage& image,
59       ImageDecodedCallback callback) override {
60     ImageDecodeRequestId request_id = next_image_request_id_++;
61
62     decoded_images_.push_back(image);
63     decodes_requested_.insert(image.paint_image().stable_id());
64     locked_images_.insert(request_id);
65
66     // Post the callback asynchronously to match the behaviour in
67     // ImageController.
68     worker_task_runner_->PostTask(
69         FROM_HERE, base::BindOnce(std::move(callback), request_id,
70                                   ImageDecodeResult::SUCCESS));
71
72     return request_id;
73   }
74
75  private:
76   ImageDecodeRequestId next_image_request_id_ = 1U;
77   std::unordered_set<ImageDecodeRequestId> locked_images_;
78   PaintImageIdFlatSet decodes_requested_;
79   std::vector<DrawImage> decoded_images_;
80 };
81
82 class CheckerImageTrackerTest : public testing::Test,
83                                 public CheckerImageTrackerClient {
84  public:
85   enum class ImageType {
86     CHECKERABLE,
87     SMALL_NON_CHECKERABLE,
88     LARGE_NON_CHECKERABLE
89   };
90
91   void SetUpTracker(bool checker_images_enabled) {
92     size_t size_to_checker = 512 * 1024;
93     checker_image_tracker_ = std::make_unique<CheckerImageTracker>(
94         &image_controller_, this, checker_images_enabled, size_to_checker);
95     checker_image_tracker_->SetMaxDecodePriorityAllowed(
96         CheckerImageTracker::DecodeType::kPreDecode);
97   }
98
99   void TearDown() override { checker_image_tracker_.reset(); }
100
101   DrawImage CreateImage(
102       ImageType image_type,
103       PaintImage::AnimationType animation = PaintImage::AnimationType::STATIC,
104       PaintImage::CompletionState completion =
105           PaintImage::CompletionState::DONE,
106       bool is_multipart = false) {
107     int dimension = 0;
108     switch (image_type) {
109       case ImageType::CHECKERABLE:
110         dimension = kCheckerableImageDimension;
111         break;
112       case ImageType::SMALL_NON_CHECKERABLE:
113         dimension = kSmallNonCheckerableImageDimension;
114         break;
115       case ImageType::LARGE_NON_CHECKERABLE:
116         dimension = kLargeNonCheckerableImageDimension;
117         break;
118     }
119
120     auto generator = CreatePaintImageGenerator(gfx::Size(dimension, dimension));
121     auto id = PaintImage::GetNextId();
122     checker_image_tracker_->UpdateImageDecodingHints(
123         {{id, PaintImage::DecodingMode::kAsync}});
124     return DrawImage(PaintImageBuilder::WithDefault()
125                          .set_id(id)
126                          .set_paint_image_generator(std::move(generator))
127                          .set_animation_type(animation)
128                          .set_completion_state(completion)
129                          .set_is_multipart(is_multipart)
130                          .set_decoding_mode(PaintImage::DecodingMode::kAsync)
131                          .TakePaintImage(),
132                      false, SkIRect::MakeWH(dimension, dimension),
133                      PaintFlags::FilterQuality::kNone, SkM44(),
134                      PaintImage::kDefaultFrameIndex, kDefaultTargetColorParams);
135   }
136
137   bool ShouldCheckerImage(const DrawImage& draw_image, WhichTree tree) {
138     return checker_image_tracker_->ShouldCheckerImage(draw_image, tree);
139   }
140
141   CheckerImageTracker::ImageDecodeQueue BuildImageDecodeQueue(
142       std::vector<DrawImage> images,
143       WhichTree tree) {
144     CheckerImageTracker::ImageDecodeQueue decode_queue;
145     for (const auto& image : images) {
146       if (ShouldCheckerImage(image, tree))
147         decode_queue.push_back(CheckerImageTracker::ImageDecodeRequest(
148             image.paint_image(), CheckerImageTracker::DecodeType::kRaster));
149     }
150     return decode_queue;
151   }
152
153   // CheckerImageTrackerClient implementation.
154   void NeedsInvalidationForCheckerImagedTiles() override {
155     invalidation_request_pending_ = true;
156   }
157
158  protected:
159   TestImageController image_controller_;
160   std::unique_ptr<CheckerImageTracker> checker_image_tracker_;
161
162   bool invalidation_request_pending_ = false;
163 };
164
165 TEST_F(CheckerImageTrackerTest, CheckerImagesDisabled) {
166   // Ensures that the tracker doesn't filter any images for checkering if it is
167   // disabled.
168   SetUpTracker(false);
169
170   PaintImageIdFlatSet checkered_images;
171   DrawImage draw_image = CreateImage(ImageType::CHECKERABLE);
172   EXPECT_FALSE(ShouldCheckerImage(draw_image, WhichTree::PENDING_TREE));
173   EXPECT_EQ(image_controller_.num_of_locked_images(), 0);
174 }
175
176 TEST_F(CheckerImageTrackerTest, UpdatesImagesAtomically) {
177   // Ensures that the tracker updates images atomically for each frame.
178   SetUpTracker(true);
179
180   DrawImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
181   DrawImage small_non_checkerable_image =
182       CreateImage(ImageType::SMALL_NON_CHECKERABLE);
183   DrawImage large_non_checkerable_image =
184       CreateImage(ImageType::LARGE_NON_CHECKERABLE);
185   CheckerImageTracker::ImageDecodeQueue image_decode_queue;
186
187   // First request to filter images.
188   std::vector<DrawImage> draw_images = {
189       checkerable_image, small_non_checkerable_image,
190       large_non_checkerable_image, checkerable_image};
191   image_decode_queue =
192       BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
193
194   ASSERT_EQ(2u, image_decode_queue.size());
195   EXPECT_EQ(checkerable_image.paint_image(), image_decode_queue[0].paint_image);
196   EXPECT_EQ(checkerable_image.paint_image(), image_decode_queue[1].paint_image);
197
198   checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
199   EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
200
201   // Run pending task to indicate completion of decode request to the tracker.
202   // This should send an impl-side invalidation request to the client. The
203   // images must remain locked until the sync tree to which the invalidations
204   // are added is activated.
205   base::RunLoop().RunUntilIdle();
206   EXPECT_TRUE(invalidation_request_pending_);
207   EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
208
209   // Continue checkering the image until the set of images to invalidate is
210   // pulled.
211   EXPECT_TRUE(ShouldCheckerImage(checkerable_image, WhichTree::PENDING_TREE));
212
213   PaintImageIdFlatSet invalidated_images =
214       checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
215   EXPECT_EQ(invalidated_images.size(), 1U);
216   EXPECT_EQ(
217       invalidated_images.count(checkerable_image.paint_image().stable_id()),
218       1U);
219
220   // Use the same set of draw images to ensure that they are not checkered on
221   // the pending tree now.
222   EXPECT_FALSE(ShouldCheckerImage(checkerable_image, WhichTree::PENDING_TREE));
223   EXPECT_FALSE(
224       ShouldCheckerImage(small_non_checkerable_image, WhichTree::PENDING_TREE));
225   EXPECT_FALSE(
226       ShouldCheckerImage(large_non_checkerable_image, WhichTree::PENDING_TREE));
227
228   // Use this set to make the same request from the active tree, we should
229   // continue checkering this image on the active tree until activation.
230   EXPECT_TRUE(ShouldCheckerImage(checkerable_image, WhichTree::ACTIVE_TREE));
231   EXPECT_FALSE(
232       ShouldCheckerImage(small_non_checkerable_image, WhichTree::ACTIVE_TREE));
233   EXPECT_FALSE(
234       ShouldCheckerImage(large_non_checkerable_image, WhichTree::ACTIVE_TREE));
235
236   // Activate the sync tree. The images should be unlocked upon activation.
237   EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
238   checker_image_tracker_->DidActivateSyncTree();
239 }
240
241 TEST_F(CheckerImageTrackerTest, NoConsecutiveCheckeringForImage) {
242   // Ensures that if an image is decoded and invalidated once, it is not
243   // checkered again in subsequent frames.
244   SetUpTracker(true);
245
246   DrawImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
247   std::vector<DrawImage> draw_images = {checkerable_image};
248
249   CheckerImageTracker::ImageDecodeQueue image_decode_queue =
250       BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
251   EXPECT_EQ(image_decode_queue.size(), 1U);
252   checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
253
254   // Trigger decode completion, take images to invalidate and activate the sync
255   // tree.
256   base::RunLoop().RunUntilIdle();
257   checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
258   checker_image_tracker_->DidActivateSyncTree();
259
260   // Subsequent requests for this image should not be checkered.
261   EXPECT_FALSE(ShouldCheckerImage(checkerable_image, WhichTree::PENDING_TREE));
262 }
263
264 TEST_F(CheckerImageTrackerTest,
265        TracksCheckeredImagesSeperatelyInConsecutiveFrames) {
266   // Ensures that the set of images being checkered on the pending tree, and the
267   // active tree are tracked correctly.
268   SetUpTracker(true);
269
270   DrawImage checkerable_image1 = CreateImage(ImageType::CHECKERABLE);
271   std::vector<DrawImage> draw_images;
272   CheckerImageTracker::ImageDecodeQueue image_decode_queue;
273
274   // First request to filter images on the pending and active tree.
275   draw_images.push_back(checkerable_image1);
276   image_decode_queue =
277       BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
278   EXPECT_EQ(image_decode_queue.size(), 1U);
279   checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
280
281   // The image is also checkered on the active tree while a decode request is
282   // pending.
283   EXPECT_TRUE(ShouldCheckerImage(checkerable_image1, WhichTree::ACTIVE_TREE));
284
285   // Trigger decode completion and take images to invalidate on the sync tree.
286   base::RunLoop().RunUntilIdle();
287   EXPECT_TRUE(invalidation_request_pending_);
288   PaintImageIdFlatSet invalidated_images =
289       checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
290   EXPECT_EQ(invalidated_images.size(), 1U);
291   EXPECT_EQ(
292       invalidated_images.count(checkerable_image1.paint_image().stable_id()),
293       1U);
294
295   // Second request to filter the same image on the pending and active tree. It
296   // should be checkered on the active tree, but not the pending tree.
297   EXPECT_TRUE(ShouldCheckerImage(checkerable_image1, WhichTree::ACTIVE_TREE));
298   EXPECT_FALSE(ShouldCheckerImage(checkerable_image1, WhichTree::PENDING_TREE));
299
300   // New checkerable image on the pending tree.
301   DrawImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
302   EXPECT_TRUE(ShouldCheckerImage(checkerable_image2, WhichTree::PENDING_TREE));
303
304   // Activate the sync tree. The initial image should no longer be checkered on
305   // the active tree.
306   checker_image_tracker_->DidActivateSyncTree();
307   EXPECT_FALSE(ShouldCheckerImage(checkerable_image1, WhichTree::ACTIVE_TREE));
308 }
309
310 TEST_F(CheckerImageTrackerTest, CancelsScheduledDecodes) {
311   SetUpTracker(true);
312
313   DrawImage checkerable_image1 = CreateImage(ImageType::CHECKERABLE);
314   DrawImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
315   std::vector<DrawImage> draw_images = {checkerable_image1, checkerable_image2};
316
317   CheckerImageTracker::ImageDecodeQueue image_decode_queue;
318   image_decode_queue =
319       BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
320   EXPECT_EQ(image_decode_queue.size(), 2U);
321   checker_image_tracker_->ScheduleImageDecodeQueue(
322       std::move(image_decode_queue));
323
324   // Only the first image in the queue should have been decoded.
325   EXPECT_EQ(image_controller_.decodes_requested().size(), 1U);
326   EXPECT_EQ(image_controller_.decodes_requested().count(
327                 checkerable_image1.paint_image().stable_id()),
328             1U);
329
330   // Rebuild the queue before the tracker is notified of decode completion,
331   // removing the second image and adding a new one.
332   DrawImage checkerable_image3 = CreateImage(ImageType::CHECKERABLE);
333   draw_images = {checkerable_image1, checkerable_image3};
334   image_decode_queue =
335       BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
336
337   // The queue has 2 decodes because we are still checkering on the first one.
338   EXPECT_EQ(image_decode_queue.size(), 2U);
339   checker_image_tracker_->ScheduleImageDecodeQueue(
340       std::move(image_decode_queue));
341
342   // We still have only one decode because the tracker keeps only one decode
343   // pending at a time.
344   EXPECT_EQ(image_controller_.decodes_requested().size(), 1U);
345   EXPECT_EQ(image_controller_.decodes_requested().count(
346                 checkerable_image1.paint_image().stable_id()),
347             1U);
348
349   // Trigger completion for all decodes. Only 2 images should have been decoded
350   // since the second image was cancelled.
351   base::RunLoop().RunUntilIdle();
352   EXPECT_EQ(image_controller_.decodes_requested().size(), 2U);
353   EXPECT_EQ(image_controller_.decodes_requested().count(
354                 checkerable_image3.paint_image().stable_id()),
355             1U);
356   EXPECT_EQ(image_controller_.num_of_locked_images(), 2);
357 }
358
359 TEST_F(CheckerImageTrackerTest, ClearsTracker) {
360   SetUpTracker(true);
361
362   DrawImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
363   CheckerImageTracker::ImageDecodeQueue image_decode_queue =
364       BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
365   EXPECT_EQ(image_decode_queue.size(), 1U);
366   checker_image_tracker_->ScheduleImageDecodeQueue(
367       std::move(image_decode_queue));
368   base::RunLoop().RunUntilIdle();
369   checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
370
371   // The image is no longer checkered on the pending tree.
372   image_decode_queue =
373       BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
374   EXPECT_EQ(image_decode_queue.size(), 0U);
375   EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
376
377   // Clear the tracker without clearing the async decode tracking. This should
378   // drop the decode but the image should not be checkered.
379   bool can_clear_decode_policy_tracking = false;
380   checker_image_tracker_->ClearTracker(can_clear_decode_policy_tracking);
381   EXPECT_EQ(image_controller_.num_of_locked_images(), 0);
382   image_decode_queue =
383       BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
384   EXPECT_EQ(image_decode_queue.size(), 0U);
385   checker_image_tracker_->DidActivateSyncTree();
386
387   // Now clear the decode tracking as well. The image will be re-checkered.
388   can_clear_decode_policy_tracking = true;
389   checker_image_tracker_->ClearTracker(can_clear_decode_policy_tracking);
390   // Re-initialize the decoding hint state. The decode policy tracking should
391   // only be done when all image state will be re-created, so is safe to purge.
392   checker_image_tracker_->UpdateImageDecodingHints(
393       {{checkerable_image.paint_image().stable_id(),
394         PaintImage::DecodingMode::kAsync}});
395   image_decode_queue =
396       BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
397   EXPECT_EQ(image_decode_queue.size(), 1U);
398
399   // If an image had been decoded and tracker was cleared after it, we should
400   // continue checkering it.
401   DrawImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
402   image_decode_queue =
403       BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
404   EXPECT_EQ(image_decode_queue.size(), 1U);
405   checker_image_tracker_->ScheduleImageDecodeQueue(
406       std::move(image_decode_queue));
407   base::RunLoop().RunUntilIdle();
408
409   EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
410   can_clear_decode_policy_tracking = false;
411   checker_image_tracker_->ClearTracker(can_clear_decode_policy_tracking);
412   EXPECT_EQ(image_controller_.num_of_locked_images(), 0);
413   image_decode_queue =
414       BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
415   EXPECT_EQ(image_decode_queue.size(), 1U);
416 }
417
418 TEST_F(CheckerImageTrackerTest, CheckersOnlyStaticCompletedImages) {
419   SetUpTracker(true);
420
421   DrawImage static_image = CreateImage(ImageType::CHECKERABLE);
422   DrawImage animated_image =
423       CreateImage(ImageType::CHECKERABLE, PaintImage::AnimationType::ANIMATED);
424   DrawImage partial_image =
425       CreateImage(ImageType::CHECKERABLE, PaintImage::AnimationType::STATIC,
426                   PaintImage::CompletionState::PARTIALLY_DONE);
427   DrawImage video_image =
428       CreateImage(ImageType::CHECKERABLE, PaintImage::AnimationType::VIDEO);
429   std::vector<DrawImage> draw_images = {static_image, animated_image,
430                                         partial_image, video_image};
431
432   CheckerImageTracker::ImageDecodeQueue image_decode_queue =
433       BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
434   EXPECT_EQ(image_decode_queue.size(), 1U);
435   EXPECT_EQ(image_decode_queue[0].paint_image, static_image.paint_image());
436
437   // Change the partial image to complete and try again. It should sstill not
438   // be checkered.
439   gfx::Size image_size = gfx::Size(partial_image.paint_image().width(),
440                                    partial_image.paint_image().height());
441   DrawImage completed_paint_image = DrawImage(
442       PaintImageBuilder::WithDefault()
443           .set_id(partial_image.paint_image().stable_id())
444           .set_paint_image_generator(CreatePaintImageGenerator(image_size))
445           .TakePaintImage(),
446       false, SkIRect::MakeWH(image_size.width(), image_size.height()),
447       PaintFlags::FilterQuality::kNone, SkM44(), PaintImage::kDefaultFrameIndex,
448       kDefaultTargetColorParams);
449   EXPECT_FALSE(
450       ShouldCheckerImage(completed_paint_image, WhichTree::PENDING_TREE));
451 }
452
453 TEST_F(CheckerImageTrackerTest, DontCheckerDisallowedImages) {
454   SetUpTracker(true);
455
456   DrawImage image = CreateImage(ImageType::CHECKERABLE);
457   EXPECT_TRUE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
458   checker_image_tracker_->DisallowCheckeringForImage(image.paint_image());
459   // Since the tracker already saw the image, even disallowing it would still
460   // ensure that we checker it until it's completed.
461   EXPECT_TRUE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
462
463   // Reset the tracker.
464   checker_image_tracker_->ClearTracker(true);
465   // If we haven't seen the image and disallow it first, then it's not
466   // checkerable anymore.
467   checker_image_tracker_->DisallowCheckeringForImage(image.paint_image());
468   EXPECT_FALSE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
469 }
470
471 TEST_F(CheckerImageTrackerTest, ChoosesMaxScaleAndQuality) {
472   SetUpTracker(true);
473
474   DrawImage image = CreateImage(ImageType::CHECKERABLE);
475   DrawImage scaled_image1(image, 0.5f, PaintImage::kDefaultFrameIndex,
476                           TargetColorParams());
477   DrawImage scaled_image2 =
478       DrawImage(image.paint_image(), false, image.src_rect(),
479                 PaintFlags::FilterQuality::kHigh, SkM44::Scale(1.8f, 1.8f),
480                 PaintImage::kDefaultFrameIndex, kDefaultTargetColorParams);
481
482   std::vector<DrawImage> draw_images = {scaled_image1, scaled_image2};
483   CheckerImageTracker::ImageDecodeQueue image_decode_queue =
484       BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
485   checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
486   EXPECT_EQ(image_controller_.decoded_images().size(), 1u);
487   EXPECT_EQ(image_controller_.decoded_images()[0].scale(),
488             SkSize::Make(1.8f, 1.8f));
489   EXPECT_EQ(image_controller_.decoded_images()[0].filter_quality(),
490             PaintFlags::FilterQuality::kHigh);
491 }
492
493 TEST_F(CheckerImageTrackerTest, DontCheckerMultiPartImages) {
494   SetUpTracker(true);
495
496   DrawImage image = CreateImage(ImageType::CHECKERABLE);
497   EXPECT_FALSE(image.paint_image().is_multipart());
498   DrawImage multi_part_image =
499       CreateImage(ImageType::CHECKERABLE, PaintImage::AnimationType::STATIC,
500                   PaintImage::CompletionState::DONE, true);
501   EXPECT_TRUE(multi_part_image.paint_image().is_multipart());
502
503   EXPECT_TRUE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
504   EXPECT_FALSE(ShouldCheckerImage(multi_part_image, WhichTree::PENDING_TREE));
505 }
506
507 TEST_F(CheckerImageTrackerTest, RespectsDecodePriority) {
508   SetUpTracker(true);
509
510   DrawImage image1 = CreateImage(ImageType::CHECKERABLE);
511   DrawImage image2 = CreateImage(ImageType::CHECKERABLE);
512   DrawImage image3 = CreateImage(ImageType::CHECKERABLE);
513   DrawImage image4 = CreateImage(ImageType::CHECKERABLE);
514   CheckerImageTracker::ImageDecodeQueue image_decode_queue =
515       BuildImageDecodeQueue({image1, image2, image3, image4},
516                             WhichTree::PENDING_TREE);
517
518   // Mark the last 2 images as pre-decode.
519   EXPECT_EQ(image_decode_queue.size(), 4u);
520   image_decode_queue[2].type = CheckerImageTracker::DecodeType::kPreDecode;
521   image_decode_queue[3].type = CheckerImageTracker::DecodeType::kPreDecode;
522
523   // No decodes allowed. Nothing should be scheduled.
524   EXPECT_EQ(image_controller_.decoded_images().size(), 0u);
525   checker_image_tracker_->SetNoDecodesAllowed();
526   checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
527   EXPECT_EQ(image_controller_.decoded_images().size(), 0u);
528
529   // Raster decodes allowed. Only those should be scheduled.
530   checker_image_tracker_->SetMaxDecodePriorityAllowed(
531       CheckerImageTracker::DecodeType::kRaster);
532   base::RunLoop().RunUntilIdle();
533   EXPECT_EQ(image_controller_.decoded_images().size(), 2u);
534   EXPECT_EQ(image_controller_.decoded_images()[0], image1);
535   EXPECT_EQ(image_controller_.decoded_images()[1], image2);
536
537   // All decodes allowed. The complete queue should be flushed.
538   checker_image_tracker_->SetMaxDecodePriorityAllowed(
539       CheckerImageTracker::DecodeType::kPreDecode);
540   base::RunLoop().RunUntilIdle();
541   EXPECT_EQ(image_controller_.decoded_images()[0], image1);
542   EXPECT_EQ(image_controller_.decoded_images()[1], image2);
543   EXPECT_EQ(image_controller_.decoded_images()[2], image3);
544   EXPECT_EQ(image_controller_.decoded_images()[3], image4);
545 }
546
547 TEST_F(CheckerImageTrackerTest, UseSrcRectForSize) {
548   SetUpTracker(true);
549
550   // Create an image with checkerable dimensions and subrect it. It should not
551   // be checkered.
552   DrawImage image = CreateImage(ImageType::CHECKERABLE);
553   image =
554       DrawImage(image.paint_image(), false, SkIRect::MakeWH(200, 200),
555                 image.filter_quality(), SkM44(), PaintImage::kDefaultFrameIndex,
556                 image.target_color_params());
557   EXPECT_FALSE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
558 }
559
560 TEST_F(CheckerImageTrackerTest, DisableForSoftwareRaster) {
561   SetUpTracker(true);
562
563   // Should checker when not disabled.
564   checker_image_tracker_->set_force_disabled(false);
565   DrawImage image1 = CreateImage(ImageType::CHECKERABLE);
566   EXPECT_TRUE(ShouldCheckerImage(image1, WhichTree::PENDING_TREE));
567
568   // Toggle disable. If we were already checkering this image, we need to
569   // continue it.
570   checker_image_tracker_->set_force_disabled(true);
571   EXPECT_TRUE(ShouldCheckerImage(image1, WhichTree::PENDING_TREE));
572
573   // New image should not be checkered while disabled.
574   DrawImage image2 = CreateImage(ImageType::CHECKERABLE);
575   EXPECT_FALSE(ShouldCheckerImage(image2, WhichTree::PENDING_TREE));
576 }
577
578 TEST_F(CheckerImageTrackerTest, DecodingModeHints) {
579   SetUpTracker(true);
580
581   base::flat_map<PaintImage::Id, PaintImage::DecodingMode> hints = {
582       {1, PaintImage::DecodingMode::kUnspecified},
583       {2, PaintImage::DecodingMode::kSync},
584       {3, PaintImage::DecodingMode::kAsync}};
585   checker_image_tracker_->UpdateImageDecodingHints(hints);
586
587   EXPECT_EQ(PaintImage::DecodingMode::kUnspecified,
588             checker_image_tracker_->get_decoding_mode_hint_for_testing(1));
589   EXPECT_EQ(PaintImage::DecodingMode::kSync,
590             checker_image_tracker_->get_decoding_mode_hint_for_testing(2));
591   EXPECT_EQ(PaintImage::DecodingMode::kAsync,
592             checker_image_tracker_->get_decoding_mode_hint_for_testing(3));
593
594   hints = {{1, PaintImage::DecodingMode::kAsync},
595            {2, PaintImage::DecodingMode::kAsync},
596            {3, PaintImage::DecodingMode::kAsync}};
597   checker_image_tracker_->UpdateImageDecodingHints(hints);
598
599   // The more conservative state should persist.
600   EXPECT_EQ(PaintImage::DecodingMode::kUnspecified,
601             checker_image_tracker_->get_decoding_mode_hint_for_testing(1));
602   EXPECT_EQ(PaintImage::DecodingMode::kSync,
603             checker_image_tracker_->get_decoding_mode_hint_for_testing(2));
604   EXPECT_EQ(PaintImage::DecodingMode::kAsync,
605             checker_image_tracker_->get_decoding_mode_hint_for_testing(3));
606
607   hints = {{1, PaintImage::DecodingMode::kUnspecified},
608            {2, PaintImage::DecodingMode::kUnspecified},
609            {3, PaintImage::DecodingMode::kUnspecified}};
610   checker_image_tracker_->UpdateImageDecodingHints(hints);
611
612   EXPECT_EQ(PaintImage::DecodingMode::kUnspecified,
613             checker_image_tracker_->get_decoding_mode_hint_for_testing(1));
614   EXPECT_EQ(PaintImage::DecodingMode::kSync,
615             checker_image_tracker_->get_decoding_mode_hint_for_testing(2));
616   EXPECT_EQ(PaintImage::DecodingMode::kUnspecified,
617             checker_image_tracker_->get_decoding_mode_hint_for_testing(3));
618
619   hints = {{1, PaintImage::DecodingMode::kSync}};
620   checker_image_tracker_->UpdateImageDecodingHints(hints);
621
622   EXPECT_EQ(PaintImage::DecodingMode::kSync,
623             checker_image_tracker_->get_decoding_mode_hint_for_testing(1));
624   EXPECT_EQ(PaintImage::DecodingMode::kSync,
625             checker_image_tracker_->get_decoding_mode_hint_for_testing(2));
626   EXPECT_EQ(PaintImage::DecodingMode::kUnspecified,
627             checker_image_tracker_->get_decoding_mode_hint_for_testing(3));
628 }
629
630 TEST_F(CheckerImageTrackerTest, UsageHintsMakeImagesSync) {
631   SetUpTracker(true);
632
633   DrawImage image = CreateImage(ImageType::CHECKERABLE);
634   EXPECT_TRUE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
635
636   base::flat_map<PaintImage::Id, PaintImage::DecodingMode> hints = {
637       {image.paint_image().stable_id(), PaintImage::DecodingMode::kSync}};
638   checker_image_tracker_->UpdateImageDecodingHints(hints);
639
640   auto invalidated = checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
641   ASSERT_EQ(invalidated.size(), 1u);
642   EXPECT_EQ(*invalidated.begin(), image.paint_image().stable_id());
643
644   EXPECT_FALSE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
645   // We should still continue checkering on the active tree, since we want
646   // atomic updates from the pending tree.
647   EXPECT_TRUE(ShouldCheckerImage(image, WhichTree::ACTIVE_TREE));
648 }
649
650 }  // namespace
651 }  // namespace cc