OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "chrome/common/chrome_notification_types.h" | 9 #include "chrome/common/chrome_notification_types.h" |
10 #include "chrome/common/extensions/extension.h" | 10 #include "chrome/common/extensions/extension.h" |
11 #include "chrome/common/extensions/extension_resource.h" | 11 #include "chrome/common/extensions/extension_resource.h" |
12 #include "content/public/browser/browser_thread.h" | 12 #include "content/public/browser/browser_thread.h" |
13 #include "content/public/browser/notification_service.h" | 13 #include "content/public/browser/notification_service.h" |
14 #include "skia/ext/image_operations.h" | 14 #include "skia/ext/image_operations.h" |
15 #include "third_party/skia/include/core/SkBitmap.h" | 15 #include "third_party/skia/include/core/SkBitmap.h" |
| 16 #include "ui/gfx/image/image.h" |
16 #include "webkit/glue/image_decoder.h" | 17 #include "webkit/glue/image_decoder.h" |
17 | 18 |
18 using content::BrowserThread; | 19 using content::BrowserThread; |
19 | 20 |
| 21 //////////////////////////////////////////////////////////////////////////////// |
| 22 // ImageLoadingTracker::Observer |
| 23 |
20 ImageLoadingTracker::Observer::~Observer() {} | 24 ImageLoadingTracker::Observer::~Observer() {} |
21 | 25 |
22 //////////////////////////////////////////////////////////////////////////////// | 26 //////////////////////////////////////////////////////////////////////////////// |
| 27 // ImageLoadingTracker::ImageInfo |
| 28 |
| 29 ImageLoadingTracker::ImageInfo::ImageInfo( |
| 30 const ExtensionResource resource, gfx::Size max_size) |
| 31 : resource(resource), max_size(max_size) { |
| 32 } |
| 33 |
| 34 ImageLoadingTracker::ImageInfo::~ImageInfo() { |
| 35 } |
| 36 |
| 37 //////////////////////////////////////////////////////////////////////////////// |
| 38 // ImageLoadingTracker::PendingLoadInfo |
| 39 |
| 40 ImageLoadingTracker::PendingLoadInfo::PendingLoadInfo() |
| 41 : extension(NULL), |
| 42 pending_count(0) { |
| 43 } |
| 44 |
| 45 ImageLoadingTracker::PendingLoadInfo::~PendingLoadInfo() { |
| 46 } |
| 47 |
| 48 //////////////////////////////////////////////////////////////////////////////// |
23 // ImageLoadingTracker::ImageLoader | 49 // ImageLoadingTracker::ImageLoader |
24 | 50 |
25 // A RefCounted class for loading images on the File thread and reporting back | 51 // A RefCounted class for loading images on the File thread and reporting back |
26 // on the UI thread. | 52 // on the UI thread. |
27 class ImageLoadingTracker::ImageLoader | 53 class ImageLoadingTracker::ImageLoader |
28 : public base::RefCountedThreadSafe<ImageLoader> { | 54 : public base::RefCountedThreadSafe<ImageLoader> { |
29 public: | 55 public: |
30 explicit ImageLoader(ImageLoadingTracker* tracker) | 56 explicit ImageLoader(ImageLoadingTracker* tracker) |
31 : tracker_(tracker) { | 57 : tracker_(tracker) { |
32 CHECK(BrowserThread::GetCurrentThreadIdentifier(&callback_thread_id_)); | 58 CHECK(BrowserThread::GetCurrentThreadIdentifier(&callback_thread_id_)); |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 callback_thread_id_, FROM_HERE, | 121 callback_thread_id_, FROM_HERE, |
96 base::Bind(&ImageLoader::ReportOnUIThread, this, | 122 base::Bind(&ImageLoader::ReportOnUIThread, this, |
97 image, resource, original_size, id)); | 123 image, resource, original_size, id)); |
98 } | 124 } |
99 | 125 |
100 void ReportOnUIThread(SkBitmap* image, const ExtensionResource& resource, | 126 void ReportOnUIThread(SkBitmap* image, const ExtensionResource& resource, |
101 const gfx::Size& original_size, int id) { | 127 const gfx::Size& original_size, int id) { |
102 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 128 DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
103 | 129 |
104 if (tracker_) | 130 if (tracker_) |
105 tracker_->OnImageLoaded(image, resource, original_size, id); | 131 tracker_->OnImageLoaded(image, resource, original_size, id, true); |
106 | 132 |
107 delete image; | 133 delete image; |
108 } | 134 } |
109 | 135 |
110 private: | 136 private: |
111 // The tracker we are loading the image for. If NULL, it means the tracker is | 137 // The tracker we are loading the image for. If NULL, it means the tracker is |
112 // no longer interested in the reply. | 138 // no longer interested in the reply. |
113 ImageLoadingTracker* tracker_; | 139 ImageLoadingTracker* tracker_; |
114 | 140 |
115 // The thread that we need to call back on to report that we are done. | 141 // The thread that we need to call back on to report that we are done. |
(...skipping 16 matching lines...) Expand all Loading... |
132 // The loader is created lazily and is NULL if the tracker is destroyed before | 158 // The loader is created lazily and is NULL if the tracker is destroyed before |
133 // any valid image load tasks have been posted. | 159 // any valid image load tasks have been posted. |
134 if (loader_) | 160 if (loader_) |
135 loader_->StopTracking(); | 161 loader_->StopTracking(); |
136 } | 162 } |
137 | 163 |
138 void ImageLoadingTracker::LoadImage(const Extension* extension, | 164 void ImageLoadingTracker::LoadImage(const Extension* extension, |
139 const ExtensionResource& resource, | 165 const ExtensionResource& resource, |
140 const gfx::Size& max_size, | 166 const gfx::Size& max_size, |
141 CacheParam cache) { | 167 CacheParam cache) { |
142 // If we don't have a path we don't need to do any further work, just respond | 168 std::vector<ImageInfo> info_list; |
143 // back. | 169 info_list.push_back(ImageInfo(resource, max_size)); |
| 170 LoadImages(extension, info_list, cache); |
| 171 } |
| 172 |
| 173 void ImageLoadingTracker::LoadImages(const Extension* extension, |
| 174 const std::vector<ImageInfo>& info_list, |
| 175 CacheParam cache) { |
| 176 PendingLoadInfo load_info; |
| 177 load_info.extension = extension; |
| 178 load_info.cache = cache; |
| 179 load_info.extension_id = extension->id(); |
| 180 load_info.pending_count = info_list.size(); |
144 int id = next_id_++; | 181 int id = next_id_++; |
145 if (resource.relative_path().empty()) { | 182 load_map_[id] = load_info; |
146 OnImageLoaded(NULL, resource, max_size, id); | 183 |
147 return; | 184 for (std::vector<ImageInfo>::const_iterator it = info_list.begin(); |
| 185 it != info_list.end(); ++it) { |
| 186 // If we don't have a path we don't need to do any further work, just |
| 187 // respond back. |
| 188 if (it->resource.relative_path().empty()) { |
| 189 OnImageLoaded(NULL, it->resource, it->max_size, id, false); |
| 190 continue; |
| 191 } |
| 192 |
| 193 DCHECK(extension->path() == it->resource.extension_root()); |
| 194 |
| 195 // See if the extension has the image already. |
| 196 if (extension->HasCachedImage(it->resource, it->max_size)) { |
| 197 SkBitmap image = extension->GetCachedImage(it->resource, it->max_size); |
| 198 OnImageLoaded(&image, it->resource, it->max_size, id, false); |
| 199 continue; |
| 200 } |
| 201 |
| 202 // Instruct the ImageLoader to load this on the File thread. LoadImage does |
| 203 // not block. |
| 204 if (!loader_) |
| 205 loader_ = new ImageLoader(this); |
| 206 loader_->LoadImage(it->resource, it->max_size, id); |
148 } | 207 } |
149 | |
150 DCHECK(extension->path() == resource.extension_root()); | |
151 | |
152 // See if the extension has the image already. | |
153 if (extension->HasCachedImage(resource, max_size)) { | |
154 SkBitmap image = extension->GetCachedImage(resource, max_size); | |
155 OnImageLoaded(&image, resource, max_size, id); | |
156 return; | |
157 } | |
158 | |
159 if (cache == CACHE) | |
160 load_map_[id] = extension; | |
161 | |
162 // Instruct the ImageLoader to load this on the File thread. LoadImage does | |
163 // not block. | |
164 if (!loader_) | |
165 loader_ = new ImageLoader(this); | |
166 loader_->LoadImage(resource, max_size, id); | |
167 } | 208 } |
168 | 209 |
169 void ImageLoadingTracker::OnImageLoaded( | 210 void ImageLoadingTracker::OnImageLoaded( |
170 SkBitmap* image, | 211 SkBitmap* image, |
171 const ExtensionResource& resource, | 212 const ExtensionResource& resource, |
172 const gfx::Size& original_size, | 213 const gfx::Size& original_size, |
173 int id) { | 214 int id, |
174 LoadMap::iterator i = load_map_.find(id); | 215 bool should_cache) { |
175 if (i != load_map_.end()) { | 216 LoadMap::iterator load_map_it = load_map_.find(id); |
176 i->second->SetCachedImage(resource, image ? *image : SkBitmap(), | 217 DCHECK(load_map_it != load_map_.end()); |
177 original_size); | 218 PendingLoadInfo* info = &load_map_it->second; |
178 load_map_.erase(i); | 219 |
| 220 // Save the pending results. |
| 221 DCHECK(info->pending_count > 0); |
| 222 info->pending_count--; |
| 223 if (image) |
| 224 info->bitmaps.push_back(*image); |
| 225 |
| 226 // Add to the extension's image cache if requested. |
| 227 DCHECK(info->cache != CACHE || info->extension); |
| 228 if (should_cache && info->cache == CACHE && |
| 229 !info->extension->HasCachedImage(resource, original_size)) { |
| 230 info->extension->SetCachedImage(resource, image ? *image : SkBitmap(), |
| 231 original_size); |
179 } | 232 } |
180 | 233 |
181 observer_->OnImageLoaded(image, resource, id); | 234 // If all pending images are done then report back. |
| 235 if (info->pending_count == 0) { |
| 236 gfx::Image image; |
| 237 std::string extension_id = info->extension_id; |
| 238 |
| 239 if (info->bitmaps.size() > 0) { |
| 240 std::vector<const SkBitmap*> bitmaps; |
| 241 for (std::vector<SkBitmap>::const_iterator it = info->bitmaps.begin(); |
| 242 it != info->bitmaps.end(); ++it) { |
| 243 // gfx::Image takes ownership of this bitmap. |
| 244 bitmaps.push_back(new SkBitmap(*it)); |
| 245 } |
| 246 image = gfx::Image(bitmaps); |
| 247 } |
| 248 |
| 249 load_map_.erase(load_map_it); |
| 250 |
| 251 // ImageLoadingTracker might be deleted after the callback so don't |
| 252 // anything after this statement. |
| 253 observer_->OnImageLoaded(image, extension_id, id); |
| 254 } |
182 } | 255 } |
183 | 256 |
184 void ImageLoadingTracker::Observe(int type, | 257 void ImageLoadingTracker::Observe(int type, |
185 const content::NotificationSource& source, | 258 const content::NotificationSource& source, |
186 const content::NotificationDetails& details) { | 259 const content::NotificationDetails& details) { |
187 DCHECK(type == chrome::NOTIFICATION_EXTENSION_UNLOADED); | 260 DCHECK(type == chrome::NOTIFICATION_EXTENSION_UNLOADED); |
188 | 261 |
189 const Extension* extension = | 262 const Extension* extension = |
190 content::Details<UnloadedExtensionInfo>(details)->extension; | 263 content::Details<UnloadedExtensionInfo>(details)->extension; |
191 | 264 |
192 // Remove all entries in the load_map_ referencing the extension. This ensures | 265 // Remove reference to this extension from all pending load entries. This |
193 // we don't attempt to cache the image when the load completes. | 266 // ensures we don't attempt to cache the image when the load completes. |
194 for (LoadMap::iterator i = load_map_.begin(); i != load_map_.end();) { | 267 for (LoadMap::iterator i = load_map_.begin(); i != load_map_.end(); ++i) { |
195 if (i->second == extension) | 268 PendingLoadInfo* info = &i->second; |
196 load_map_.erase(i++); | 269 if (info->extension == extension) { |
197 else | 270 info->extension = NULL; |
198 ++i; | 271 info->cache = DONT_CACHE; |
| 272 } |
199 } | 273 } |
200 } | 274 } |
OLD | NEW |