Cast: Stop logging kVideoFrameSentToEncoder and rename a couple events.
[chromium-blink-merge.git] / chrome / browser / extensions / image_loader.cc
blob055775b8a6b1583bdfced806b297f814f9f81824
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.
5 #include "chrome/browser/extensions/image_loader.h"
7 #include <map>
8 #include <vector>
10 #include "base/callback.h"
11 #include "base/compiler_specific.h"
12 #include "base/file_util.h"
13 #include "base/lazy_instance.h"
14 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/threading/sequenced_worker_pool.h"
17 #include "chrome/browser/extensions/image_loader_factory.h"
18 #include "chrome/common/chrome_paths.h"
19 #include "content/public/browser/browser_thread.h"
20 #include "extensions/common/extension.h"
21 #include "grit/chrome_unscaled_resources.h"
22 #include "grit/component_extension_resources_map.h"
23 #include "grit/theme_resources.h"
24 #include "skia/ext/image_operations.h"
25 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/gfx/codec/png_codec.h"
27 #include "ui/gfx/image/image_family.h"
28 #include "ui/gfx/image/image_skia.h"
30 #if defined(OS_CHROMEOS)
31 #include "ui/file_manager/file_manager_resource_util.h"
32 #endif
34 #if defined(USE_AURA)
35 #include "ui/keyboard/keyboard_util.h"
36 #endif
38 using content::BrowserThread;
39 using extensions::Extension;
40 using extensions::ImageLoader;
41 using extensions::Manifest;
43 namespace {
45 bool ShouldResizeImageRepresentation(
46 ImageLoader::ImageRepresentation::ResizeCondition resize_method,
47 const gfx::Size& decoded_size,
48 const gfx::Size& desired_size) {
49 switch (resize_method) {
50 case ImageLoader::ImageRepresentation::ALWAYS_RESIZE:
51 return decoded_size != desired_size;
52 case ImageLoader::ImageRepresentation::RESIZE_WHEN_LARGER:
53 return decoded_size.width() > desired_size.width() ||
54 decoded_size.height() > desired_size.height();
55 case ImageLoader::ImageRepresentation::NEVER_RESIZE:
56 return false;
57 default:
58 NOTREACHED();
59 return false;
63 SkBitmap ResizeIfNeeded(const SkBitmap& bitmap,
64 const ImageLoader::ImageRepresentation& image_info) {
65 gfx::Size original_size(bitmap.width(), bitmap.height());
66 if (ShouldResizeImageRepresentation(image_info.resize_condition,
67 original_size,
68 image_info.desired_size)) {
69 return skia::ImageOperations::Resize(
70 bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
71 image_info.desired_size.width(), image_info.desired_size.height());
74 return bitmap;
77 void LoadResourceOnUIThread(int resource_id, SkBitmap* bitmap) {
78 DCHECK_CURRENTLY_ON(BrowserThread::UI);
80 gfx::ImageSkia image(
81 *ResourceBundle::GetSharedInstance().GetImageSkiaNamed(resource_id));
82 image.MakeThreadSafe();
83 *bitmap = *image.bitmap();
86 void LoadImageOnBlockingPool(const ImageLoader::ImageRepresentation& image_info,
87 SkBitmap* bitmap) {
88 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
90 // Read the file from disk.
91 std::string file_contents;
92 base::FilePath path = image_info.resource.GetFilePath();
93 if (path.empty() || !base::ReadFileToString(path, &file_contents)) {
94 return;
97 const unsigned char* data =
98 reinterpret_cast<const unsigned char*>(file_contents.data());
99 // Note: This class only decodes bitmaps from extension resources. Chrome
100 // doesn't (for security reasons) directly load extension resources provided
101 // by the extension author, but instead decodes them in a separate
102 // locked-down utility process. Only if the decoding succeeds is the image
103 // saved from memory to disk and subsequently used in the Chrome UI.
104 // Chrome is therefore decoding bitmaps here that were generated by Chrome.
105 gfx::PNGCodec::Decode(data, file_contents.length(), bitmap);
108 // Add the resources from |entries| (there are |size| of them) to
109 // |path_to_resource_id| after normalizing separators.
110 void AddComponentResourceEntries(
111 std::map<base::FilePath, int>* path_to_resource_id,
112 const GritResourceMap* entries,
113 size_t size) {
114 for (size_t i = 0; i < size; ++i) {
115 base::FilePath resource_path = base::FilePath().AppendASCII(
116 entries[i].name);
117 resource_path = resource_path.NormalizePathSeparators();
119 DCHECK(path_to_resource_id->find(resource_path) ==
120 path_to_resource_id->end());
121 (*path_to_resource_id)[resource_path] = entries[i].value;
125 std::vector<SkBitmap> LoadResourceBitmaps(
126 const Extension* extension,
127 const std::vector<ImageLoader::ImageRepresentation>& info_list) {
128 // Loading resources has to happen on the UI thread. So do this first, and
129 // pass the rest of the work off as a blocking pool task.
130 std::vector<SkBitmap> bitmaps;
131 bitmaps.resize(info_list.size());
133 int i = 0;
134 for (std::vector<ImageLoader::ImageRepresentation>::const_iterator
135 it = info_list.begin();
136 it != info_list.end();
137 ++it, ++i) {
138 DCHECK(it->resource.relative_path().empty() ||
139 extension->path() == it->resource.extension_root());
141 int resource_id;
142 if (extension->location() == Manifest::COMPONENT &&
143 ImageLoader::IsComponentExtensionResource(
144 extension->path(), it->resource.relative_path(), &resource_id)) {
145 LoadResourceOnUIThread(resource_id, &bitmaps[i]);
148 return bitmaps;
151 } // namespace
153 namespace extensions {
155 ////////////////////////////////////////////////////////////////////////////////
156 // ImageLoader::ImageRepresentation
158 ImageLoader::ImageRepresentation::ImageRepresentation(
159 const ExtensionResource& resource,
160 ResizeCondition resize_condition,
161 const gfx::Size& desired_size,
162 ui::ScaleFactor scale_factor)
163 : resource(resource),
164 resize_condition(resize_condition),
165 desired_size(desired_size),
166 scale_factor(scale_factor) {
169 ImageLoader::ImageRepresentation::~ImageRepresentation() {
172 ////////////////////////////////////////////////////////////////////////////////
173 // ImageLoader::LoadResult
175 struct ImageLoader::LoadResult {
176 LoadResult(const SkBitmap& bitmap,
177 const gfx::Size& original_size,
178 const ImageRepresentation& image_representation);
179 ~LoadResult();
181 SkBitmap bitmap;
182 gfx::Size original_size;
183 ImageRepresentation image_representation;
186 ImageLoader::LoadResult::LoadResult(
187 const SkBitmap& bitmap,
188 const gfx::Size& original_size,
189 const ImageLoader::ImageRepresentation& image_representation)
190 : bitmap(bitmap),
191 original_size(original_size),
192 image_representation(image_representation) {
195 ImageLoader::LoadResult::~LoadResult() {
198 namespace {
200 // Need to be after ImageRepresentation and LoadResult are defined.
201 std::vector<ImageLoader::LoadResult> LoadImagesOnBlockingPool(
202 const std::vector<ImageLoader::ImageRepresentation>& info_list,
203 const std::vector<SkBitmap>& bitmaps) {
204 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
205 std::vector<ImageLoader::LoadResult> load_result;
207 for (size_t i = 0; i < info_list.size(); ++i) {
208 const ImageLoader::ImageRepresentation& image = info_list[i];
210 // If we don't have a path there isn't anything we can do, just skip it.
211 if (image.resource.relative_path().empty())
212 continue;
214 SkBitmap bitmap;
215 if (bitmaps[i].isNull())
216 LoadImageOnBlockingPool(image, &bitmap);
217 else
218 bitmap = bitmaps[i];
220 // If the image failed to load, skip it.
221 if (bitmap.isNull() || bitmap.empty())
222 continue;
224 gfx::Size original_size(bitmap.width(), bitmap.height());
225 bitmap = ResizeIfNeeded(bitmap, image);
227 load_result.push_back(
228 ImageLoader::LoadResult(bitmap, original_size, image));
231 return load_result;
234 } // namespace
236 ////////////////////////////////////////////////////////////////////////////////
237 // ImageLoader
239 ImageLoader::ImageLoader()
240 : weak_ptr_factory_(this) {
243 ImageLoader::~ImageLoader() {
246 // static
247 ImageLoader* ImageLoader::Get(content::BrowserContext* context) {
248 return ImageLoaderFactory::GetForBrowserContext(context);
251 // A map from a resource path to the resource ID. Used only by
252 // IsComponentExtensionResource below.
253 static base::LazyInstance<std::map<base::FilePath, int> > path_to_resource_id =
254 LAZY_INSTANCE_INITIALIZER;
256 // static
257 bool ImageLoader::IsComponentExtensionResource(
258 const base::FilePath& extension_path,
259 const base::FilePath& resource_path,
260 int* resource_id) {
261 static const GritResourceMap kExtraComponentExtensionResources[] = {
262 {"web_store/webstore_icon_128.png", IDR_WEBSTORE_ICON},
263 {"web_store/webstore_icon_16.png", IDR_WEBSTORE_ICON_16},
264 {"chrome_app/product_logo_128.png", IDR_PRODUCT_LOGO_128},
265 {"chrome_app/product_logo_16.png", IDR_PRODUCT_LOGO_16},
266 #if defined(ENABLE_SETTINGS_APP)
267 {"settings_app/settings_app_icon_128.png", IDR_SETTINGS_APP_ICON_128},
268 {"settings_app/settings_app_icon_16.png", IDR_SETTINGS_APP_ICON_16},
269 {"settings_app/settings_app_icon_32.png", IDR_SETTINGS_APP_ICON_32},
270 {"settings_app/settings_app_icon_48.png", IDR_SETTINGS_APP_ICON_48},
271 #endif
274 if (path_to_resource_id.Get().empty()) {
275 AddComponentResourceEntries(
276 path_to_resource_id.Pointer(),
277 kComponentExtensionResources,
278 kComponentExtensionResourcesSize);
279 AddComponentResourceEntries(
280 path_to_resource_id.Pointer(),
281 kExtraComponentExtensionResources,
282 arraysize(kExtraComponentExtensionResources));
283 #if defined(OS_CHROMEOS)
284 size_t file_manager_resource_size;
285 const GritResourceMap* file_manager_resources =
286 file_manager::GetFileManagerResources(&file_manager_resource_size);
287 AddComponentResourceEntries(
288 path_to_resource_id.Pointer(),
289 file_manager_resources,
290 file_manager_resource_size);
292 size_t keyboard_resource_size;
293 const GritResourceMap* keyboard_resources =
294 keyboard::GetKeyboardExtensionResources(&keyboard_resource_size);
295 AddComponentResourceEntries(
296 path_to_resource_id.Pointer(),
297 keyboard_resources,
298 keyboard_resource_size);
299 #endif
302 base::FilePath directory_path = extension_path;
303 base::FilePath resources_dir;
304 base::FilePath relative_path;
305 if (!PathService::Get(chrome::DIR_RESOURCES, &resources_dir) ||
306 !resources_dir.AppendRelativePath(directory_path, &relative_path)) {
307 return false;
309 relative_path = relative_path.Append(resource_path);
310 relative_path = relative_path.NormalizePathSeparators();
312 std::map<base::FilePath, int>::const_iterator entry =
313 path_to_resource_id.Get().find(relative_path);
314 if (entry != path_to_resource_id.Get().end())
315 *resource_id = entry->second;
317 return entry != path_to_resource_id.Get().end();
320 void ImageLoader::LoadImageAsync(const Extension* extension,
321 const ExtensionResource& resource,
322 const gfx::Size& max_size,
323 const ImageLoaderImageCallback& callback) {
324 std::vector<ImageRepresentation> info_list;
325 info_list.push_back(ImageRepresentation(
326 resource,
327 ImageRepresentation::RESIZE_WHEN_LARGER,
328 max_size,
329 ui::SCALE_FACTOR_100P));
330 LoadImagesAsync(extension, info_list, callback);
333 void ImageLoader::LoadImagesAsync(
334 const Extension* extension,
335 const std::vector<ImageRepresentation>& info_list,
336 const ImageLoaderImageCallback& callback) {
337 DCHECK_CURRENTLY_ON(BrowserThread::UI);
338 DCHECK(!BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
339 base::PostTaskAndReplyWithResult(
340 BrowserThread::GetBlockingPool(),
341 FROM_HERE,
342 base::Bind(LoadImagesOnBlockingPool,
343 info_list,
344 LoadResourceBitmaps(extension, info_list)),
345 base::Bind(
346 &ImageLoader::ReplyBack, weak_ptr_factory_.GetWeakPtr(), callback));
349 void ImageLoader::LoadImageFamilyAsync(
350 const extensions::Extension* extension,
351 const std::vector<ImageRepresentation>& info_list,
352 const ImageLoaderImageFamilyCallback& callback) {
353 DCHECK_CURRENTLY_ON(BrowserThread::UI);
354 DCHECK(!BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
355 base::PostTaskAndReplyWithResult(
356 BrowserThread::GetBlockingPool(),
357 FROM_HERE,
358 base::Bind(LoadImagesOnBlockingPool,
359 info_list,
360 LoadResourceBitmaps(extension, info_list)),
361 base::Bind(&ImageLoader::ReplyBackWithImageFamily,
362 weak_ptr_factory_.GetWeakPtr(),
363 callback));
366 void ImageLoader::ReplyBack(const ImageLoaderImageCallback& callback,
367 const std::vector<LoadResult>& load_result) {
368 DCHECK_CURRENTLY_ON(BrowserThread::UI);
370 gfx::ImageSkia image_skia;
372 for (std::vector<LoadResult>::const_iterator it = load_result.begin();
373 it != load_result.end(); ++it) {
374 const SkBitmap& bitmap = it->bitmap;
375 const ImageRepresentation& image_rep = it->image_representation;
377 image_skia.AddRepresentation(gfx::ImageSkiaRep(
378 bitmap,
379 ui::GetImageScale(image_rep.scale_factor)));
382 gfx::Image image;
383 if (!image_skia.isNull()) {
384 image_skia.MakeThreadSafe();
385 image = gfx::Image(image_skia);
388 callback.Run(image);
391 void ImageLoader::ReplyBackWithImageFamily(
392 const ImageLoaderImageFamilyCallback& callback,
393 const std::vector<LoadResult>& load_result) {
394 DCHECK_CURRENTLY_ON(BrowserThread::UI);
396 std::map<std::pair<int, int>, gfx::ImageSkia> image_skia_map;
397 gfx::ImageFamily image_family;
399 for (std::vector<LoadResult>::const_iterator it = load_result.begin();
400 it != load_result.end();
401 ++it) {
402 const SkBitmap& bitmap = it->bitmap;
403 const ImageRepresentation& image_rep = it->image_representation;
404 const std::pair<int, int> key = std::make_pair(
405 image_rep.desired_size.width(), image_rep.desired_size.height());
406 // Create a new ImageSkia for this width/height, or add a representation to
407 // an existing ImageSkia with the same width/height.
408 image_skia_map[key].AddRepresentation(
409 gfx::ImageSkiaRep(bitmap, ui::GetImageScale(image_rep.scale_factor)));
412 for (std::map<std::pair<int, int>, gfx::ImageSkia>::iterator it =
413 image_skia_map.begin();
414 it != image_skia_map.end();
415 ++it) {
416 it->second.MakeThreadSafe();
417 image_family.Add(it->second);
420 callback.Run(image_family);
423 } // namespace extensions