Chromium Code Reviews| Index: chrome/browser/extensions/image_loading_tracker.cc |
| =================================================================== |
| --- chrome/browser/extensions/image_loading_tracker.cc (revision 42362) |
| +++ chrome/browser/extensions/image_loading_tracker.cc (working copy) |
| @@ -1,60 +1,55 @@ |
| -// Copyright (c) 2009 The Chromium Authors. All rights reserved. |
| +// Copyright (c) 2010 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 "chrome/browser/extensions/image_loading_tracker.h" |
| #include "base/file_util.h" |
| -#include "base/logging.h" |
| -#include "base/message_loop.h" |
| -#include "base/scoped_ptr.h" |
| -#include "base/task.h" |
| -#include "base/thread.h" |
| #include "chrome/browser/chrome_thread.h" |
| #include "chrome/common/extensions/extension_resource.h" |
| -#include "gfx/size.h" |
| #include "skia/ext/image_operations.h" |
| #include "third_party/skia/include/core/SkBitmap.h" |
| #include "webkit/glue/image_decoder.h" |
| //////////////////////////////////////////////////////////////////////////////// |
| -// ImageLoadingTracker::LoadImageTask |
| +// ImageLoadingTracker::ImageLoader |
| -// The LoadImageTask is for asynchronously loading the image on the file thread. |
| -// If the image is successfully loaded and decoded it will report back on the |
| -// calling thread to let the caller know the image is done loading. |
| -class ImageLoadingTracker::LoadImageTask : public Task { |
| +// A RefCounted class for loading images on the File thread and reporting back |
| +// on the UI thread. |
| +class ImageLoadingTracker::ImageLoader |
| + : public base::RefCountedThreadSafe<ImageLoader> { |
| public: |
| - // Constructor for the LoadImageTask class. |tracker| is the object that |
| - // we use to communicate back to the entity that wants the image after we |
| - // decode it. |path| is the path to load the image from. |max_size| is the |
| - // maximum size for the loaded image. It will be resized to fit this if |
| - // larger. |index| is an identifier for the image that we pass back to the |
| - // caller. |
| - LoadImageTask(ImageLoadingTracker* tracker, |
| - const ExtensionResource& resource, |
| - const gfx::Size& max_size, |
| - size_t index) |
| - : tracker_(tracker), |
| - resource_(resource), |
| - max_size_(max_size), |
| - index_(index) { |
| - CHECK(ChromeThread::GetCurrentThreadIdentifier(&callback_thread_id_)); |
| + explicit ImageLoader(ImageLoadingTracker* tracker) |
| + : tracker_(tracker) { |
| } |
| - void ReportBack(SkBitmap* image) { |
| + // Lets this class know that the tracker is no longer interested in the |
| + // results. |
| + void StopTracking() { |
| + tracker_ = NULL; |
| + } |
| + |
| + // Instructs the loader to load a task on the File thread. |
| + void LoadImage(const ExtensionResource& resource, |
| + const gfx::Size& max_size, |
| + int index) { |
| + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| ChromeThread::PostTask( |
| - callback_thread_id_, FROM_HERE, |
| - NewRunnableMethod( |
| - tracker_, &ImageLoadingTracker::OnImageLoaded, image, index_)); |
| + ChromeThread::FILE, FROM_HERE, |
| + NewRunnableMethod(this, &ImageLoader::LoadOnFileThread, resource, |
| + max_size, index)); |
| } |
| - virtual void Run() { |
| + void LoadOnFileThread(const ExtensionResource& resource, |
| + const gfx::Size& max_size, |
| + int index) { |
| + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| + |
| // Read the file from disk. |
| std::string file_contents; |
| - FilePath path = resource_.GetFilePath(); |
| + FilePath path = resource.GetFilePath(); |
| if (path.empty() || !file_util::ReadFileToString(path, &file_contents)) { |
| - ReportBack(NULL); |
| + ReportBack(NULL, index); |
| return; |
| } |
| @@ -65,55 +60,79 @@ |
| scoped_ptr<SkBitmap> decoded(new SkBitmap()); |
| *decoded = decoder.Decode(data, file_contents.length()); |
| if (decoded->empty()) { |
| - ReportBack(NULL); |
| + ReportBack(NULL, index); |
| return; // Unable to decode. |
| } |
| - if (decoded->width() > max_size_.width() || |
| - decoded->height() > max_size_.height()) { |
| + if (decoded->width() > max_size.width() || |
| + decoded->height() > max_size.height()) { |
| // The bitmap is too big, re-sample. |
| *decoded = skia::ImageOperations::Resize( |
| *decoded, skia::ImageOperations::RESIZE_LANCZOS3, |
| - max_size_.width(), max_size_.height()); |
| + max_size.width(), max_size.height()); |
| } |
| - ReportBack(decoded.release()); |
| + ReportBack(decoded.release(), index); |
| } |
| - private: |
| - // The thread that we need to call back on to report that we are done. |
| - ChromeThread::ID callback_thread_id_; |
| + void ReportBack(SkBitmap* image, size_t index) { |
| + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE)); |
| - // The object that is waiting for us to respond back. |
| - ImageLoadingTracker* tracker_; |
| + ChromeThread::PostTask( |
| + ChromeThread::UI, FROM_HERE, |
| + NewRunnableMethod(this, &ImageLoader::ReportOnUIThread, image, index)); |
| + } |
| - // The image resource to load asynchronously. |
| - ExtensionResource resource_; |
| + void ReportOnUIThread(SkBitmap* image, int index) { |
| + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| - // The max size for the loaded image. |
| - gfx::Size max_size_; |
| + if (tracker_) |
| + tracker_->OnImageLoaded(image, index); |
| - // The index of the icon being loaded. |
| - size_t index_; |
| + if (image) |
| + delete image; |
| + } |
| + |
| + private: |
| + // The tracker we are loading the image for. If NULL, it means the tracker is |
| + // no longer interested in the reply. |
| + ImageLoadingTracker* tracker_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(ImageLoader); |
| }; |
| //////////////////////////////////////////////////////////////////////////////// |
| // ImageLoadingTracker |
| -void ImageLoadingTracker::PostLoadImageTask(const ExtensionResource& resource, |
| - const gfx::Size& max_size) { |
| - ChromeThread::PostTask( |
| - ChromeThread::FILE, FROM_HERE, |
| - new LoadImageTask(this, resource, max_size, posted_count_++)); |
| +ImageLoadingTracker::ImageLoadingTracker(Observer* observer) |
| + : observer_(observer) { |
| + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| } |
| -void ImageLoadingTracker::OnImageLoaded(SkBitmap* image, size_t index) { |
| - if (observer_) |
| - observer_->OnImageLoaded(image, index); |
| +ImageLoadingTracker::~ImageLoadingTracker() { |
| + // The loader is created lazily and is NULL if the tracker is destroyed before |
| + // any valid image load tasks have been posted. |
| + if (loader_) |
| + loader_->StopTracking(); |
| +} |
| - if (image) |
| - delete image; |
| +void ImageLoadingTracker::PostLoadImageTask(const ExtensionResource& resource, |
|
Aaron Boodman
2010/03/23 19:10:55
Nit: I think you could simply this name to just Lo
|
| + const gfx::Size& max_size, |
| + int index) { |
| + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| - if (--image_count_ == 0) |
| - Release(); // We are no longer needed. |
| + // If we don't have a path we don't need to do any further work, just respond |
| + // back. |
| + if (resource.relative_path().empty()) |
| + OnImageLoaded(NULL, index); |
| + |
| + if (!loader_) |
| + loader_ = new ImageLoader(this); |
| + loader_->LoadImage(resource, max_size, index); |
| } |
| + |
| +void ImageLoadingTracker::OnImageLoaded(SkBitmap* image, int index) { |
| + DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI)); |
| + |
| + observer_->OnImageLoaded(image, index); |
| +} |