| Index: cc/tiles/checker_image_tracker.cc
 | 
| diff --git a/cc/tiles/checker_image_tracker.cc b/cc/tiles/checker_image_tracker.cc
 | 
| new file mode 100644
 | 
| index 0000000000000000000000000000000000000000..c081132e6ece23c5e9569af2dc37968d9e69e5cb
 | 
| --- /dev/null
 | 
| +++ b/cc/tiles/checker_image_tracker.cc
 | 
| @@ -0,0 +1,152 @@
 | 
| +// Copyright 2017 The Chromium Authors. All rights reserved.
 | 
| +// Use of this source code is governed by a BSD-style license that can be
 | 
| +// found in the LICENSE file.
 | 
| +
 | 
| +#include "cc/tiles/checker_image_tracker.h"
 | 
| +
 | 
| +#include "base/bind.h"
 | 
| +#include "base/trace_event/trace_event.h"
 | 
| +
 | 
| +namespace cc {
 | 
| +namespace {
 | 
| +// The minimum size of an image that we should consider checkering.
 | 
| +size_t kMinImageSizeToCheckerBytes = 512 * 1024;
 | 
| +
 | 
| +size_t SafeSizeOfImage(const SkImage* image) {
 | 
| +  base::CheckedNumeric<size_t> checked_size = 4;
 | 
| +  checked_size *= image->width();
 | 
| +  checked_size *= image->height();
 | 
| +  return checked_size.ValueOrDefault(std::numeric_limits<size_t>::max());
 | 
| +}
 | 
| +
 | 
| +}  // namespace
 | 
| +
 | 
| +CheckerImageTracker::CheckerImageTracker(ImageController* image_controller,
 | 
| +                                         CheckerImageTrackerClient* client,
 | 
| +                                         bool enable_checker_imaging)
 | 
| +    : image_controller_(image_controller),
 | 
| +      client_(client),
 | 
| +      enable_checker_imaging_(enable_checker_imaging),
 | 
| +      weak_factory_(this) {}
 | 
| +
 | 
| +CheckerImageTracker::~CheckerImageTracker() {
 | 
| +  // Unlock all images pending decode requests.
 | 
| +  for (auto it : image_id_to_decode_request_id_)
 | 
| +    image_controller_->UnlockImageDecode(it.second);
 | 
| +}
 | 
| +
 | 
| +void CheckerImageTracker::FilterImagesForCheckeringForTile(
 | 
| +    std::vector<DrawImage>* images,
 | 
| +    ImageIdFlatSet* checkered_images,
 | 
| +    WhichTree tree) {
 | 
| +  DCHECK(checkered_images->empty());
 | 
| +
 | 
| +  auto images_to_checker = std::remove_if(
 | 
| +      images->begin(), images->end(),
 | 
| +      [this, tree, &checkered_images](const DrawImage& draw_image) {
 | 
| +        const sk_sp<const SkImage>& image = draw_image.image();
 | 
| +        DCHECK(image->isLazyGenerated());
 | 
| +        if (ShouldCheckerImage(image, tree)) {
 | 
| +          ScheduleImageDecodeIfNecessary(image);
 | 
| +          checkered_images->insert(image->uniqueID());
 | 
| +          return true;
 | 
| +        }
 | 
| +        return false;
 | 
| +      });
 | 
| +  images->erase(images_to_checker, images->end());
 | 
| +}
 | 
| +
 | 
| +const ImageIdFlatSet& CheckerImageTracker::TakeImagesToInvalidateOnSyncTree() {
 | 
| +  DCHECK_EQ(invalidated_images_on_current_sync_tree_.size(), 0u)
 | 
| +      << "Sync tree can not be invalidated more than once";
 | 
| +
 | 
| +  invalidated_images_on_current_sync_tree_.swap(images_pending_invalidation_);
 | 
| +  images_pending_invalidation_.clear();
 | 
| +  return invalidated_images_on_current_sync_tree_;
 | 
| +}
 | 
| +
 | 
| +void CheckerImageTracker::DidActivateSyncTree() {
 | 
| +  for (auto image_id : invalidated_images_on_current_sync_tree_) {
 | 
| +    auto it = image_id_to_decode_request_id_.find(image_id);
 | 
| +    image_controller_->UnlockImageDecode(it->second);
 | 
| +    image_id_to_decode_request_id_.erase(it);
 | 
| +  }
 | 
| +
 | 
| +  invalidated_images_on_current_sync_tree_.clear();
 | 
| +}
 | 
| +
 | 
| +void CheckerImageTracker::DidFinishImageDecode(
 | 
| +    ImageId image_id,
 | 
| +    ImageController::ImageDecodeRequestId request_id) {
 | 
| +  TRACE_EVENT_ASYNC_END0("cc", "CheckerImageTracker::DeferImageDecode",
 | 
| +                         image_id);
 | 
| +
 | 
| +  DCHECK_NE(pending_image_decodes_.count(image_id), 0u);
 | 
| +  pending_image_decodes_.erase(image_id);
 | 
| +
 | 
| +  images_decoded_once_.insert(image_id);
 | 
| +  images_pending_invalidation_.insert(image_id);
 | 
| +  client_->NeedsInvalidationForCheckerImagedTiles();
 | 
| +}
 | 
| +
 | 
| +bool CheckerImageTracker::ShouldCheckerImage(const sk_sp<const SkImage>& image,
 | 
| +                                             WhichTree tree) const {
 | 
| +  TRACE_EVENT1("cc", "CheckerImageTracker::ShouldCheckerImage", "image_id",
 | 
| +               image->uniqueID());
 | 
| +
 | 
| +  if (!enable_checker_imaging_)
 | 
| +    return false;
 | 
| +
 | 
| +  // If the image was invalidated on the current sync tree and the tile is
 | 
| +  // for the active tree, continue checkering it on the active tree to ensure
 | 
| +  // the image update is atomic for the frame.
 | 
| +  if (invalidated_images_on_current_sync_tree_.count(image->uniqueID()) != 0 &&
 | 
| +      tree == WhichTree::ACTIVE_TREE) {
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  // If a decode request is pending for this image, continue checkering it.
 | 
| +  if (pending_image_decodes_.find(image->uniqueID()) !=
 | 
| +      pending_image_decodes_.end()) {
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  // If the image is pending invalidation, continue checkering it. All tiles
 | 
| +  // for these images will be invalidated on the next pending tree.
 | 
| +  if (images_pending_invalidation_.find(image->uniqueID()) !=
 | 
| +      images_pending_invalidation_.end()) {
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  // If the image has been decoded once before, don't checker it again.
 | 
| +  if (images_decoded_once_.find(image->uniqueID()) !=
 | 
| +      images_decoded_once_.end()) {
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  return SafeSizeOfImage(image.get()) >= kMinImageSizeToCheckerBytes;
 | 
| +}
 | 
| +
 | 
| +void CheckerImageTracker::ScheduleImageDecodeIfNecessary(
 | 
| +    const sk_sp<const SkImage>& image) {
 | 
| +  ImageId image_id = image->uniqueID();
 | 
| +
 | 
| +  // If the image has already been decoded, or a decode request is pending, we
 | 
| +  // don't need to schedule another decode.
 | 
| +  if (images_decoded_once_.count(image_id) != 0 ||
 | 
| +      pending_image_decodes_.count(image_id) != 0) {
 | 
| +    return;
 | 
| +  }
 | 
| +
 | 
| +  TRACE_EVENT_ASYNC_BEGIN0("cc", "CheckerImageTracker::DeferImageDecode",
 | 
| +                           image_id);
 | 
| +  DCHECK_EQ(image_id_to_decode_request_id_.count(image_id), 0U);
 | 
| +
 | 
| +  image_id_to_decode_request_id_[image_id] =
 | 
| +      image_controller_->QueueImageDecode(
 | 
| +          image, base::Bind(&CheckerImageTracker::DidFinishImageDecode,
 | 
| +                            weak_factory_.GetWeakPtr(), image_id));
 | 
| +  pending_image_decodes_.insert(image_id);
 | 
| +}
 | 
| +
 | 
| +}  // namespace cc
 | 
| 
 |