// Copyright 2015 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/image_decode_controller.h" #include "cc/debug/devtools_instrumentation.h" namespace cc { namespace { class ImageDecodeTaskImpl : public ImageDecodeTask { public: ImageDecodeTaskImpl(ImageDecodeController* controller, const SkImage* image, int layer_id, uint64_t source_prepare_tiles_id) : controller_(controller), image_(skia::SharePtr(image)), layer_id_(layer_id), source_prepare_tiles_id_(source_prepare_tiles_id) {} // Overridden from Task: void RunOnWorkerThread() override { TRACE_EVENT1("cc", "ImageDecodeTaskImpl::RunOnWorkerThread", "source_prepare_tiles_id", source_prepare_tiles_id_); devtools_instrumentation::ScopedImageDecodeTask image_decode_task( image_.get()); controller_->DecodeImage(image_.get()); // Release the reference after decoding image to ensure that it is not kept // alive unless needed. image_.clear(); } // Overridden from TileTask: void ScheduleOnOriginThread(TileTaskClient* client) override {} void CompleteOnOriginThread(TileTaskClient* client) override { controller_->OnImageDecodeTaskCompleted(layer_id_, image_.get(), !HasFinishedRunning()); } protected: ~ImageDecodeTaskImpl() override {} private: ImageDecodeController* controller_; skia::RefPtr image_; int layer_id_; uint64_t source_prepare_tiles_id_; DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); }; } // namespace ImageDecodeController::ImageDecodeController() {} ImageDecodeController::~ImageDecodeController() {} scoped_refptr ImageDecodeController::GetTaskForImage( const DrawImage& image, int layer_id, uint64_t prepare_tiles_id) { uint32_t generation_id = image.image()->uniqueID(); scoped_refptr& decode_task = image_decode_tasks_[layer_id][generation_id]; if (!decode_task) decode_task = CreateTaskForImage(image.image(), layer_id, prepare_tiles_id); return decode_task; } scoped_refptr ImageDecodeController::CreateTaskForImage( const SkImage* image, int layer_id, uint64_t prepare_tiles_id) { return make_scoped_refptr( new ImageDecodeTaskImpl(this, image, layer_id, prepare_tiles_id)); } void ImageDecodeController::DecodeImage(const SkImage* image) { image->preroll(); } void ImageDecodeController::AddLayerUsedCount(int layer_id) { ++used_layer_counts_[layer_id]; } void ImageDecodeController::SubtractLayerUsedCount(int layer_id) { if (--used_layer_counts_[layer_id]) return; // Clean up decode tasks once a layer is no longer used. used_layer_counts_.erase(layer_id); image_decode_tasks_.erase(layer_id); } void ImageDecodeController::OnImageDecodeTaskCompleted(int layer_id, const SkImage* image, bool was_canceled) { // If the task has successfully finished, then keep the task until the layer // is no longer in use. This ensures that we only decode a image once. // TODO(vmpstr): Remove this when decode lifetime is controlled by cc. if (!was_canceled) return; // Otherwise, we have to clean up the task so that a new one can be created if // we need to decode the image again. LayerImageTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id); if (layer_it == image_decode_tasks_.end()) return; ImageTaskMap& image_tasks = layer_it->second; ImageTaskMap::iterator task_it = image_tasks.find(image->uniqueID()); if (task_it == image_tasks.end()) return; image_tasks.erase(task_it); } } // namespace cc