Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(106)

Side by Side Diff: chrome/browser/extensions/image_loading_tracker.cc

Issue 1075006: Eliminate all UI thread decoding of extension images.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/image_loading_tracker.h" 5 #include "chrome/browser/extensions/image_loading_tracker.h"
6 6
7 #include "base/file_util.h" 7 #include "base/file_util.h"
8 #include "base/logging.h"
9 #include "base/message_loop.h"
10 #include "base/scoped_ptr.h"
11 #include "base/task.h"
12 #include "base/thread.h"
13 #include "chrome/browser/chrome_thread.h" 8 #include "chrome/browser/chrome_thread.h"
14 #include "chrome/common/extensions/extension_resource.h" 9 #include "chrome/common/extensions/extension_resource.h"
15 #include "gfx/size.h"
16 #include "skia/ext/image_operations.h" 10 #include "skia/ext/image_operations.h"
17 #include "third_party/skia/include/core/SkBitmap.h" 11 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "webkit/glue/image_decoder.h" 12 #include "webkit/glue/image_decoder.h"
19 13
20 //////////////////////////////////////////////////////////////////////////////// 14 ////////////////////////////////////////////////////////////////////////////////
21 // ImageLoadingTracker::LoadImageTask 15 // ImageLoadingTracker::ImageLoader
22 16
23 // The LoadImageTask is for asynchronously loading the image on the file thread. 17 // A RefCounted class for loading images on the File thread and reporting back
24 // If the image is successfully loaded and decoded it will report back on the 18 // on the UI thread.
25 // calling thread to let the caller know the image is done loading. 19 class ImageLoadingTracker::ImageLoader
26 class ImageLoadingTracker::LoadImageTask : public Task { 20 : public base::RefCountedThreadSafe<ImageLoader> {
27 public: 21 public:
28 // Constructor for the LoadImageTask class. |tracker| is the object that 22 explicit ImageLoader(ImageLoadingTracker* tracker)
29 // we use to communicate back to the entity that wants the image after we 23 : tracker_(tracker) {
30 // decode it. |path| is the path to load the image from. |max_size| is the
31 // maximum size for the loaded image. It will be resized to fit this if
32 // larger. |index| is an identifier for the image that we pass back to the
33 // caller.
34 LoadImageTask(ImageLoadingTracker* tracker,
35 const ExtensionResource& resource,
36 const gfx::Size& max_size,
37 size_t index)
38 : tracker_(tracker),
39 resource_(resource),
40 max_size_(max_size),
41 index_(index) {
42 CHECK(ChromeThread::GetCurrentThreadIdentifier(&callback_thread_id_));
43 } 24 }
44 25
45 void ReportBack(SkBitmap* image) { 26 // Lets this class know that the tracker is no longer interested in the
46 ChromeThread::PostTask( 27 // results.
47 callback_thread_id_, FROM_HERE, 28 void StopTracking() {
48 NewRunnableMethod( 29 tracker_ = NULL;
49 tracker_, &ImageLoadingTracker::OnImageLoaded, image, index_));
50 } 30 }
51 31
52 virtual void Run() { 32 // Instructs the loader to load a task on the File thread.
33 void LoadImage(const ExtensionResource& resource,
34 const gfx::Size& max_size,
35 int index) {
36 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
37 ChromeThread::PostTask(
38 ChromeThread::FILE, FROM_HERE,
39 NewRunnableMethod(this, &ImageLoader::LoadOnFileThread, resource,
40 max_size, index));
41 }
42
43 void LoadOnFileThread(const ExtensionResource& resource,
44 const gfx::Size& max_size,
45 int index) {
46 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
47
53 // Read the file from disk. 48 // Read the file from disk.
54 std::string file_contents; 49 std::string file_contents;
55 FilePath path = resource_.GetFilePath(); 50 FilePath path = resource.GetFilePath();
56 if (path.empty() || !file_util::ReadFileToString(path, &file_contents)) { 51 if (path.empty() || !file_util::ReadFileToString(path, &file_contents)) {
57 ReportBack(NULL); 52 ReportBack(NULL, index);
58 return; 53 return;
59 } 54 }
60 55
61 // Decode the image using WebKit's image decoder. 56 // Decode the image using WebKit's image decoder.
62 const unsigned char* data = 57 const unsigned char* data =
63 reinterpret_cast<const unsigned char*>(file_contents.data()); 58 reinterpret_cast<const unsigned char*>(file_contents.data());
64 webkit_glue::ImageDecoder decoder; 59 webkit_glue::ImageDecoder decoder;
65 scoped_ptr<SkBitmap> decoded(new SkBitmap()); 60 scoped_ptr<SkBitmap> decoded(new SkBitmap());
66 *decoded = decoder.Decode(data, file_contents.length()); 61 *decoded = decoder.Decode(data, file_contents.length());
67 if (decoded->empty()) { 62 if (decoded->empty()) {
68 ReportBack(NULL); 63 ReportBack(NULL, index);
69 return; // Unable to decode. 64 return; // Unable to decode.
70 } 65 }
71 66
72 if (decoded->width() > max_size_.width() || 67 if (decoded->width() > max_size.width() ||
73 decoded->height() > max_size_.height()) { 68 decoded->height() > max_size.height()) {
74 // The bitmap is too big, re-sample. 69 // The bitmap is too big, re-sample.
75 *decoded = skia::ImageOperations::Resize( 70 *decoded = skia::ImageOperations::Resize(
76 *decoded, skia::ImageOperations::RESIZE_LANCZOS3, 71 *decoded, skia::ImageOperations::RESIZE_LANCZOS3,
77 max_size_.width(), max_size_.height()); 72 max_size.width(), max_size.height());
78 } 73 }
79 74
80 ReportBack(decoded.release()); 75 ReportBack(decoded.release(), index);
76 }
77
78 void ReportBack(SkBitmap* image, size_t index) {
79 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::FILE));
80
81 ChromeThread::PostTask(
82 ChromeThread::UI, FROM_HERE,
83 NewRunnableMethod(this, &ImageLoader::ReportOnUIThread, image, index));
84 }
85
86 void ReportOnUIThread(SkBitmap* image, int index) {
87 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
88
89 if (tracker_)
90 tracker_->OnImageLoaded(image, index);
91
92 if (image)
93 delete image;
81 } 94 }
82 95
83 private: 96 private:
84 // The thread that we need to call back on to report that we are done. 97 // The tracker we are loading the image for. If NULL, it means the tracker is
85 ChromeThread::ID callback_thread_id_; 98 // no longer interested in the reply.
86
87 // The object that is waiting for us to respond back.
88 ImageLoadingTracker* tracker_; 99 ImageLoadingTracker* tracker_;
89 100
90 // The image resource to load asynchronously. 101 DISALLOW_COPY_AND_ASSIGN(ImageLoader);
91 ExtensionResource resource_;
92
93 // The max size for the loaded image.
94 gfx::Size max_size_;
95
96 // The index of the icon being loaded.
97 size_t index_;
98 }; 102 };
99 103
100 //////////////////////////////////////////////////////////////////////////////// 104 ////////////////////////////////////////////////////////////////////////////////
101 // ImageLoadingTracker 105 // ImageLoadingTracker
102 106
103 void ImageLoadingTracker::PostLoadImageTask(const ExtensionResource& resource, 107 ImageLoadingTracker::ImageLoadingTracker(Observer* observer)
104 const gfx::Size& max_size) { 108 : observer_(observer) {
105 ChromeThread::PostTask( 109 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
106 ChromeThread::FILE, FROM_HERE,
107 new LoadImageTask(this, resource, max_size, posted_count_++));
108 } 110 }
109 111
110 void ImageLoadingTracker::OnImageLoaded(SkBitmap* image, size_t index) { 112 ImageLoadingTracker::~ImageLoadingTracker() {
111 if (observer_) 113 // The loader is created lazily and is NULL if the tracker is destroyed before
112 observer_->OnImageLoaded(image, index); 114 // any valid image load tasks have been posted.
115 if (loader_)
116 loader_->StopTracking();
117 }
113 118
114 if (image) 119 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
115 delete image; 120 const gfx::Size& max_size,
121 int index) {
122 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
116 123
117 if (--image_count_ == 0) 124 // If we don't have a path we don't need to do any further work, just respond
118 Release(); // We are no longer needed. 125 // back.
126 if (resource.relative_path().empty())
127 OnImageLoaded(NULL, index);
128
129 if (!loader_)
130 loader_ = new ImageLoader(this);
131 loader_->LoadImage(resource, max_size, index);
119 } 132 }
133
134 void ImageLoadingTracker::OnImageLoaded(SkBitmap* image, int index) {
135 DCHECK(ChromeThread::CurrentlyOn(ChromeThread::UI));
136
137 observer_->OnImageLoaded(image, index);
138 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698