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.
5 #include "cc/tiles/checker_image_tracker.h"
8 #include <unordered_set>
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"
22 // 5MB max image cache size.
23 const size_t kMaxImageCacheSizeBytes = 5 * 1024 * 1024;
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;
30 const TargetColorParams kDefaultTargetColorParams;
32 class TestImageController : public ImageController {
34 // We can use the same thread for the image worker because all use of it in
35 // the ImageController is over-ridden here.
37 : ImageController(base::ThreadTaskRunnerHandle::Get().get(),
38 base::ThreadTaskRunnerHandle::Get()) {
39 SetMaxImageCacheLimitBytesForTesting(kMaxImageCacheSizeBytes);
42 ~TestImageController() override { DCHECK_EQ(locked_images_.size(), 0U); }
44 int num_of_locked_images() const { return locked_images_.size(); }
45 const PaintImageIdFlatSet& decodes_requested() const {
46 return decodes_requested_;
48 const std::vector<DrawImage>& decoded_images() const {
49 return decoded_images_;
52 void UnlockImageDecode(ImageDecodeRequestId id) override {
53 DCHECK_EQ(locked_images_.count(id), 1U);
54 locked_images_.erase(id);
57 ImageDecodeRequestId QueueImageDecode(
58 const DrawImage& image,
59 ImageDecodedCallback callback) override {
60 ImageDecodeRequestId request_id = next_image_request_id_++;
62 decoded_images_.push_back(image);
63 decodes_requested_.insert(image.paint_image().stable_id());
64 locked_images_.insert(request_id);
66 // Post the callback asynchronously to match the behaviour in
68 worker_task_runner_->PostTask(
69 FROM_HERE, base::BindOnce(std::move(callback), request_id,
70 ImageDecodeResult::SUCCESS));
76 ImageDecodeRequestId next_image_request_id_ = 1U;
77 std::unordered_set<ImageDecodeRequestId> locked_images_;
78 PaintImageIdFlatSet decodes_requested_;
79 std::vector<DrawImage> decoded_images_;
82 class CheckerImageTrackerTest : public testing::Test,
83 public CheckerImageTrackerClient {
85 enum class ImageType {
87 SMALL_NON_CHECKERABLE,
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);
99 void TearDown() override { checker_image_tracker_.reset(); }
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) {
108 switch (image_type) {
109 case ImageType::CHECKERABLE:
110 dimension = kCheckerableImageDimension;
112 case ImageType::SMALL_NON_CHECKERABLE:
113 dimension = kSmallNonCheckerableImageDimension;
115 case ImageType::LARGE_NON_CHECKERABLE:
116 dimension = kLargeNonCheckerableImageDimension;
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()
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)
132 false, SkIRect::MakeWH(dimension, dimension),
133 PaintFlags::FilterQuality::kNone, SkM44(),
134 PaintImage::kDefaultFrameIndex, kDefaultTargetColorParams);
137 bool ShouldCheckerImage(const DrawImage& draw_image, WhichTree tree) {
138 return checker_image_tracker_->ShouldCheckerImage(draw_image, tree);
141 CheckerImageTracker::ImageDecodeQueue BuildImageDecodeQueue(
142 std::vector<DrawImage> images,
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));
153 // CheckerImageTrackerClient implementation.
154 void NeedsInvalidationForCheckerImagedTiles() override {
155 invalidation_request_pending_ = true;
159 TestImageController image_controller_;
160 std::unique_ptr<CheckerImageTracker> checker_image_tracker_;
162 bool invalidation_request_pending_ = false;
165 TEST_F(CheckerImageTrackerTest, CheckerImagesDisabled) {
166 // Ensures that the tracker doesn't filter any images for checkering if it is
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);
176 TEST_F(CheckerImageTrackerTest, UpdatesImagesAtomically) {
177 // Ensures that the tracker updates images atomically for each frame.
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;
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};
192 BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
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);
198 checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
199 EXPECT_EQ(image_controller_.num_of_locked_images(), 1);
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);
209 // Continue checkering the image until the set of images to invalidate is
211 EXPECT_TRUE(ShouldCheckerImage(checkerable_image, WhichTree::PENDING_TREE));
213 PaintImageIdFlatSet invalidated_images =
214 checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
215 EXPECT_EQ(invalidated_images.size(), 1U);
217 invalidated_images.count(checkerable_image.paint_image().stable_id()),
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));
224 ShouldCheckerImage(small_non_checkerable_image, WhichTree::PENDING_TREE));
226 ShouldCheckerImage(large_non_checkerable_image, WhichTree::PENDING_TREE));
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));
232 ShouldCheckerImage(small_non_checkerable_image, WhichTree::ACTIVE_TREE));
234 ShouldCheckerImage(large_non_checkerable_image, WhichTree::ACTIVE_TREE));
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();
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.
246 DrawImage checkerable_image = CreateImage(ImageType::CHECKERABLE);
247 std::vector<DrawImage> draw_images = {checkerable_image};
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);
254 // Trigger decode completion, take images to invalidate and activate the sync
256 base::RunLoop().RunUntilIdle();
257 checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
258 checker_image_tracker_->DidActivateSyncTree();
260 // Subsequent requests for this image should not be checkered.
261 EXPECT_FALSE(ShouldCheckerImage(checkerable_image, WhichTree::PENDING_TREE));
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.
270 DrawImage checkerable_image1 = CreateImage(ImageType::CHECKERABLE);
271 std::vector<DrawImage> draw_images;
272 CheckerImageTracker::ImageDecodeQueue image_decode_queue;
274 // First request to filter images on the pending and active tree.
275 draw_images.push_back(checkerable_image1);
277 BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
278 EXPECT_EQ(image_decode_queue.size(), 1U);
279 checker_image_tracker_->ScheduleImageDecodeQueue(image_decode_queue);
281 // The image is also checkered on the active tree while a decode request is
283 EXPECT_TRUE(ShouldCheckerImage(checkerable_image1, WhichTree::ACTIVE_TREE));
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);
292 invalidated_images.count(checkerable_image1.paint_image().stable_id()),
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));
300 // New checkerable image on the pending tree.
301 DrawImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
302 EXPECT_TRUE(ShouldCheckerImage(checkerable_image2, WhichTree::PENDING_TREE));
304 // Activate the sync tree. The initial image should no longer be checkered on
306 checker_image_tracker_->DidActivateSyncTree();
307 EXPECT_FALSE(ShouldCheckerImage(checkerable_image1, WhichTree::ACTIVE_TREE));
310 TEST_F(CheckerImageTrackerTest, CancelsScheduledDecodes) {
313 DrawImage checkerable_image1 = CreateImage(ImageType::CHECKERABLE);
314 DrawImage checkerable_image2 = CreateImage(ImageType::CHECKERABLE);
315 std::vector<DrawImage> draw_images = {checkerable_image1, checkerable_image2};
317 CheckerImageTracker::ImageDecodeQueue 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));
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()),
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};
335 BuildImageDecodeQueue(draw_images, WhichTree::PENDING_TREE);
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));
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()),
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()),
356 EXPECT_EQ(image_controller_.num_of_locked_images(), 2);
359 TEST_F(CheckerImageTrackerTest, ClearsTracker) {
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();
371 // The image is no longer checkered on the pending tree.
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);
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);
383 BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
384 EXPECT_EQ(image_decode_queue.size(), 0U);
385 checker_image_tracker_->DidActivateSyncTree();
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}});
396 BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
397 EXPECT_EQ(image_decode_queue.size(), 1U);
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);
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();
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);
414 BuildImageDecodeQueue({checkerable_image}, WhichTree::PENDING_TREE);
415 EXPECT_EQ(image_decode_queue.size(), 1U);
418 TEST_F(CheckerImageTrackerTest, CheckersOnlyStaticCompletedImages) {
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};
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());
437 // Change the partial image to complete and try again. It should sstill not
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))
446 false, SkIRect::MakeWH(image_size.width(), image_size.height()),
447 PaintFlags::FilterQuality::kNone, SkM44(), PaintImage::kDefaultFrameIndex,
448 kDefaultTargetColorParams);
450 ShouldCheckerImage(completed_paint_image, WhichTree::PENDING_TREE));
453 TEST_F(CheckerImageTrackerTest, DontCheckerDisallowedImages) {
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));
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));
471 TEST_F(CheckerImageTrackerTest, ChoosesMaxScaleAndQuality) {
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);
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);
493 TEST_F(CheckerImageTrackerTest, DontCheckerMultiPartImages) {
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());
503 EXPECT_TRUE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
504 EXPECT_FALSE(ShouldCheckerImage(multi_part_image, WhichTree::PENDING_TREE));
507 TEST_F(CheckerImageTrackerTest, RespectsDecodePriority) {
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);
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;
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);
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);
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);
547 TEST_F(CheckerImageTrackerTest, UseSrcRectForSize) {
550 // Create an image with checkerable dimensions and subrect it. It should not
552 DrawImage image = CreateImage(ImageType::CHECKERABLE);
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));
560 TEST_F(CheckerImageTrackerTest, DisableForSoftwareRaster) {
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));
568 // Toggle disable. If we were already checkering this image, we need to
570 checker_image_tracker_->set_force_disabled(true);
571 EXPECT_TRUE(ShouldCheckerImage(image1, WhichTree::PENDING_TREE));
573 // New image should not be checkered while disabled.
574 DrawImage image2 = CreateImage(ImageType::CHECKERABLE);
575 EXPECT_FALSE(ShouldCheckerImage(image2, WhichTree::PENDING_TREE));
578 TEST_F(CheckerImageTrackerTest, DecodingModeHints) {
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);
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));
594 hints = {{1, PaintImage::DecodingMode::kAsync},
595 {2, PaintImage::DecodingMode::kAsync},
596 {3, PaintImage::DecodingMode::kAsync}};
597 checker_image_tracker_->UpdateImageDecodingHints(hints);
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));
607 hints = {{1, PaintImage::DecodingMode::kUnspecified},
608 {2, PaintImage::DecodingMode::kUnspecified},
609 {3, PaintImage::DecodingMode::kUnspecified}};
610 checker_image_tracker_->UpdateImageDecodingHints(hints);
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));
619 hints = {{1, PaintImage::DecodingMode::kSync}};
620 checker_image_tracker_->UpdateImageDecodingHints(hints);
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));
630 TEST_F(CheckerImageTrackerTest, UsageHintsMakeImagesSync) {
633 DrawImage image = CreateImage(ImageType::CHECKERABLE);
634 EXPECT_TRUE(ShouldCheckerImage(image, WhichTree::PENDING_TREE));
636 base::flat_map<PaintImage::Id, PaintImage::DecodingMode> hints = {
637 {image.paint_image().stable_id(), PaintImage::DecodingMode::kSync}};
638 checker_image_tracker_->UpdateImageDecodingHints(hints);
640 auto invalidated = checker_image_tracker_->TakeImagesToInvalidateOnSyncTree();
641 ASSERT_EQ(invalidated.size(), 1u);
642 EXPECT_EQ(*invalidated.begin(), image.paint_image().stable_id());
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));