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

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

Issue 11027044: Add a class to replace ImageLoadingTracker with a nicer API. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: remove unused code Created 8 years, 1 month 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
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome/browser/extensions/image_loader.h"
6
7 #include "base/callback.h"
8 #include "base/file_util.h"
9 #include "base/path_service.h"
10 #include "base/string_number_conversions.h"
11 #include "base/threading/sequenced_worker_pool.h"
12 #include "chrome/common/chrome_paths.h"
13 #include "chrome/common/extensions/extension.h"
14 #include "content/public/browser/browser_thread.h"
15 #include "grit/component_extension_resources_map.h"
16 #include "grit/theme_resources.h"
17 #include "skia/ext/image_operations.h"
18 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/gfx/image/image_skia.h"
20 #include "webkit/glue/image_decoder.h"
21
22 using content::BrowserThread;
23 using extensions::Extension;
24 using extensions::ImageLoader;
25
26 namespace {
27
28 bool ShouldResizeImageRepresentation(
29 ImageLoader::ImageRepresentation::ResizeCondition resize_method,
30 const gfx::Size& decoded_size,
31 const gfx::Size& desired_size) {
32 switch (resize_method) {
33 case ImageLoader::ImageRepresentation::ALWAYS_RESIZE:
34 return decoded_size != desired_size;
35 case ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER:
36 return decoded_size.width() > desired_size.width() ||
37 decoded_size.height() > desired_size.height();
38 default:
39 NOTREACHED();
40 return false;
41 }
42 }
43
44 SkBitmap ResizeIfNeeded(const SkBitmap& bitmap,
45 const ImageLoader::ImageRepresentation& image_info) {
46 gfx::Size original_size(bitmap.width(), bitmap.height());
47 if (ShouldResizeImageRepresentation(image_info.resize_condition,
48 original_size,
49 image_info.desired_size)) {
50 return skia::ImageOperations::Resize(
51 bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
52 image_info.desired_size.width(), image_info.desired_size.height());
53 }
54
55 return bitmap;
56 }
57
58 void LoadResourceOnUIThread(int resource_id, SkBitmap* bitmap) {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
60
61 gfx::ImageSkia image(
62 *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id));
63 image.MakeThreadSafe();
64 *bitmap = *image.bitmap();
65 }
66
67 void LoadImageOnBlockingPool(const ImageLoader::ImageRepresentation& image_info,
68 SkBitmap* bitmap) {
69 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
70
71 // Read the file from disk.
72 std::string file_contents;
73 FilePath path = image_info.resource.GetFilePath();
74 if (path.empty() || !file_util::ReadFileToString(path, &file_contents)) {
75 return;
76 }
77
78 // Decode the bitmap using WebKit's image decoder.
79 const unsigned char* data =
80 reinterpret_cast<const unsigned char*>(file_contents.data());
81 webkit_glue::ImageDecoder decoder;
82 // Note: This class only decodes bitmaps from extension resources. Chrome
83 // doesn't (for security reasons) directly load extension resources provided
84 // by the extension author, but instead decodes them in a separate
85 // locked-down utility process. Only if the decoding succeeds is the image
86 // saved from memory to disk and subsequently used in the Chrome UI.
87 // Chrome is therefore decoding bitmaps here that were generated by Chrome.
88 *bitmap = decoder.Decode(data, file_contents.length());
89 }
90
91 } // namespace
92
93 namespace extensions {
94
95 ////////////////////////////////////////////////////////////////////////////////
96 // ImageLoader::ImageRepresentation
97
98 ImageLoader::ImageRepresentation::ImageRepresentation(
99 const ExtensionResource& resource,
100 ResizeCondition resize_condition,
101 const gfx::Size& desired_size,
102 ui::ScaleFactor scale_factor)
103 : resource(resource),
104 resize_condition(resize_condition),
105 desired_size(desired_size),
106 scale_factor(scale_factor) {
107 }
108
109 ImageLoader::ImageRepresentation::~ImageRepresentation() {
110 }
111
112 ////////////////////////////////////////////////////////////////////////////////
113 // ImageLoader::LoadResult
114
115 struct ImageLoader::LoadResult {
116 LoadResult(const SkBitmap& bitmap,
117 const gfx::Size& original_size,
118 const ImageRepresentation& image_representation);
119 ~LoadResult();
120
121 SkBitmap bitmap;
122 gfx::Size original_size;
123 ImageRepresentation image_representation;
124 };
125
126 ImageLoader::LoadResult::LoadResult(
127 const SkBitmap& bitmap,
128 const gfx::Size& original_size,
129 const ImageLoader::ImageRepresentation& image_representation)
130 : bitmap(bitmap),
131 original_size(original_size),
132 image_representation(image_representation) {
133 }
134
135 ImageLoader::LoadResult::~LoadResult() {
136 }
137
138 ////////////////////////////////////////////////////////////////////////////////
139 // ImageLoader
140
141 ImageLoader::ImageLoader() {
142 }
143
144 ImageLoader::~ImageLoader() {
145 }
146
147 // static
148 bool ImageLoader::IsComponentExtensionResource(const Extension* extension,
149 const FilePath& resource_path,
150 int* resource_id) {
151 static const GritResourceMap kExtraComponentExtensionResources[] = {
152 {"web_store/webstore_icon_128.png", IDR_WEBSTORE_ICON},
153 {"web_store/webstore_icon_16.png", IDR_WEBSTORE_ICON_16},
154 {"chrome_app/product_logo_128.png", IDR_PRODUCT_LOGO_128},
155 {"chrome_app/product_logo_16.png", IDR_PRODUCT_LOGO_16},
156 {"settings_app/settings_app_icon_128.png", IDR_SETTINGS_APP_ICON_128},
157 {"settings_app/settings_app_icon_16.png", IDR_SETTINGS_APP_ICON_16},
158 };
159 static const size_t kExtraComponentExtensionResourcesSize =
160 arraysize(kExtraComponentExtensionResources);
161
162 if (extension->location() != Extension::COMPONENT)
163 return false;
164
165 FilePath directory_path = extension->path();
166 FilePath resources_dir;
167 FilePath relative_path;
168 if (!PathService::Get(chrome::DIR_RESOURCES, &resources_dir) ||
169 !resources_dir.AppendRelativePath(directory_path, &relative_path)) {
170 return false;
171 }
172 relative_path = relative_path.Append(resource_path);
173 relative_path = relative_path.NormalizePathSeparators();
174
175 // TODO(tc): Make a map of FilePath -> resource ids so we don't have to
176 // covert to FilePaths all the time. This will be more useful as we add
177 // more resources.
178 for (size_t i = 0; i < kComponentExtensionResourcesSize; ++i) {
179 FilePath resource_path =
180 FilePath().AppendASCII(kComponentExtensionResources[i].name);
181 resource_path = resource_path.NormalizePathSeparators();
182
183 if (relative_path == resource_path) {
184 *resource_id = kComponentExtensionResources[i].value;
185 return true;
186 }
187 }
188 for (size_t i = 0; i < kExtraComponentExtensionResourcesSize; ++i) {
189 FilePath resource_path =
190 FilePath().AppendASCII(kExtraComponentExtensionResources[i].name);
191 resource_path = resource_path.NormalizePathSeparators();
192
193 if (relative_path == resource_path) {
194 *resource_id = kExtraComponentExtensionResources[i].value;
195 return true;
196 }
197 }
198 return false;
199 }
200
201 void ImageLoader::LoadImageAsync(
202 const Extension* extension,
203 const ExtensionResource& resource,
204 const gfx::Size& max_size,
205 const base::Callback<void(const gfx::Image&)>& callback) {
206 std::vector<ImageRepresentation> info_list;
207 info_list.push_back(ImageRepresentation(
208 resource,
209 ImageRepresentation::RESIZE_WHEN_LARGER,
210 max_size,
211 ui::SCALE_FACTOR_100P));
212 LoadImagesAsync(extension, info_list, callback);
213 }
214
215 void ImageLoader::LoadImagesAsync(
216 const Extension* extension,
217 const std::vector<ImageRepresentation>& info_list,
218 const base::Callback<void(const gfx::Image&)>& callback) {
219 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
220
221 // Loading an image from the cache and loading resources have to happen
222 // on the UI thread. So do those two things first, and pass the rest of the
223 // work of as a blocking pool task.
224
225 std::vector<SkBitmap> bitmaps;
226 bitmaps.resize(info_list.size());
227
228 int i = 0;
229 for (std::vector<ImageRepresentation>::const_iterator it = info_list.begin();
230 it != info_list.end(); ++it, ++i) {
231 DCHECK(it->resource.relative_path().empty() ||
232 extension->path() == it->resource.extension_root());
233
234 int resource_id;
235 if (IsComponentExtensionResource(extension, it->resource.relative_path(),
236 &resource_id)) {
237 LoadResourceOnUIThread(resource_id, &bitmaps[i]);
238 }
239 }
240
241 DCHECK(!BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
242 BrowserThread::PostBlockingPoolTask(
243 FROM_HERE,
244 base::Bind(&ImageLoader::LoadImagesOnBlockingPool, base::Unretained(this),
245 info_list, bitmaps, callback));
246 }
247
248 void ImageLoader::LoadImagesOnBlockingPool(
249 const std::vector<ImageRepresentation>& info_list,
250 const std::vector<SkBitmap>& bitmaps,
251 const base::Callback<void(const gfx::Image&)>& callback) {
252 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
253
254 gfx::ImageSkia image_skia;
255
256 std::vector<LoadResult> load_result;
257
258 int i = 0;
259 for (std::vector<ImageRepresentation>::const_iterator it = info_list.begin();
260 it != info_list.end(); ++it, ++i) {
261 // If we don't have a path there isn't anything we can do, just skip it.
262 if (it->resource.relative_path().empty())
263 continue;
264
265 SkBitmap bitmap;
266 if (!bitmaps[i].isNull()) {
267 bitmap = bitmaps[i];
268 } else {
269 LoadImageOnBlockingPool(*it, &bitmap);
270 }
271
272 // If the image failed to load, skip it.
273 if (bitmap.isNull() || bitmap.empty())
274 continue;
275
276 gfx::Size original_size(bitmap.width(), bitmap.height());
277 bitmap = ResizeIfNeeded(bitmap, *it);
278
279 load_result.push_back(LoadResult(bitmap, original_size, *it));
280 }
281
282 gfx::Image image;
283
284 if (!image_skia.isNull()) {
285 image_skia.MakeThreadSafe();
286 image = gfx::Image(image_skia);
287 }
288
289 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
290 base::Bind(&ImageLoader::ReplyBack,
291 base::Unretained(this), load_result,
292 callback));
293 }
294
295 void ImageLoader::ReplyBack(
296 const std::vector<LoadResult>& load_result,
297 const base::Callback<void(const gfx::Image&)>& callback) {
298 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
299
300 gfx::ImageSkia image_skia;
301
302 for (std::vector<LoadResult>::const_iterator it = load_result.begin();
303 it != load_result.end(); ++it) {
304 const SkBitmap& bitmap = it->bitmap;
305 const ImageRepresentation& image_rep = it->image_representation;
306
307 image_skia.AddRepresentation(gfx::ImageSkiaRep(
308 bitmap, image_rep.scale_factor));
309 }
310
311 gfx::Image image;
312 if (!image_skia.isNull()) {
313 image_skia.MakeThreadSafe();
314 image = gfx::Image(image_skia);
315 }
316
317 callback.Run(image);
318 }
319
320 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698