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

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

Issue 25050005: Refactored loading of applications / extensions icons. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 7 years, 2 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
OLDNEW
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_loader.h" 5 #include "chrome/browser/extensions/image_loader.h"
6 6
7 #include <map> 7 #include <map>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/base64.h"
10 #include "base/callback.h" 11 #include "base/callback.h"
11 #include "base/compiler_specific.h" 12 #include "base/compiler_specific.h"
12 #include "base/file_util.h" 13 #include "base/file_util.h"
13 #include "base/lazy_instance.h" 14 #include "base/lazy_instance.h"
14 #include "base/path_service.h" 15 #include "base/path_service.h"
15 #include "base/strings/string_number_conversions.h" 16 #include "base/strings/string_number_conversions.h"
16 #include "base/threading/sequenced_worker_pool.h" 17 #include "base/threading/sequenced_worker_pool.h"
17 #include "chrome/browser/extensions/image_loader_factory.h" 18 #include "chrome/browser/extensions/image_loader_factory.h"
19 #include "chrome/browser/favicon/favicon_service.h"
20 #include "chrome/browser/favicon/favicon_service_factory.h"
18 #include "chrome/common/chrome_paths.h" 21 #include "chrome/common/chrome_paths.h"
19 #include "chrome/common/extensions/extension.h" 22 #include "chrome/common/extensions/extension.h"
23 #include "chrome/common/extensions/extension_icon_set.h"
24 #include "chrome/common/extensions/manifest_handlers/app_launch_info.h"
25 #include "chrome/common/extensions/manifest_handlers/icons_handler.h"
20 #include "content/public/browser/browser_thread.h" 26 #include "content/public/browser/browser_thread.h"
27 #include "content/public/common/url_constants.h"
21 #include "grit/chrome_unscaled_resources.h" 28 #include "grit/chrome_unscaled_resources.h"
22 #include "grit/component_extension_resources_map.h" 29 #include "grit/component_extension_resources_map.h"
23 #include "grit/theme_resources.h" 30 #include "grit/theme_resources.h"
24 #include "skia/ext/image_operations.h" 31 #include "skia/ext/image_operations.h"
25 #include "ui/base/resource/resource_bundle.h" 32 #include "ui/base/resource/resource_bundle.h"
26 #include "ui/gfx/codec/png_codec.h" 33 #include "ui/gfx/codec/png_codec.h"
34 #include "ui/gfx/color_utils.h"
35 #include "ui/gfx/favicon_size.h"
27 #include "ui/gfx/image/image_skia.h" 36 #include "ui/gfx/image/image_skia.h"
37 #include "ui/gfx/size.h"
38 #include "ui/gfx/skbitmap_operations.h"
28 39
29 #if defined(USE_AURA) 40 #if defined(USE_AURA)
30 #include "ui/keyboard/keyboard_util.h" 41 #include "ui/keyboard/keyboard_util.h"
31 #endif 42 #endif
32 43
33 using content::BrowserThread; 44 using content::BrowserThread;
34 using extensions::Extension; 45 using extensions::Extension;
35 using extensions::ImageLoader; 46 using extensions::ImageLoader;
36 using extensions::Manifest; 47 using extensions::Manifest;
37 48
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after
108 base::FilePath resource_path = base::FilePath().AppendASCII( 119 base::FilePath resource_path = base::FilePath().AppendASCII(
109 entries[i].name); 120 entries[i].name);
110 resource_path = resource_path.NormalizePathSeparators(); 121 resource_path = resource_path.NormalizePathSeparators();
111 122
112 DCHECK(path_to_resource_id->find(resource_path) == 123 DCHECK(path_to_resource_id->find(resource_path) ==
113 path_to_resource_id->end()); 124 path_to_resource_id->end());
114 (*path_to_resource_id)[resource_path] = entries[i].value; 125 (*path_to_resource_id)[resource_path] = entries[i].value;
115 } 126 }
116 } 127 }
117 128
129 // Converts an bitmap image to a PNG representation.
130 scoped_refptr<base::RefCountedMemory> BitmapToMemory(const SkBitmap* image) {
131 base::RefCountedBytes* image_bytes = new base::RefCountedBytes;
132 gfx::PNGCodec::EncodeBGRASkBitmap(*image, false, &image_bytes->data());
133 return image_bytes;
134 }
Finnur 2013/09/30 15:11:21 This function is now both here and in extension_ic
dvh-g 2013/10/01 04:19:26 Done.
135
136 // Returns a PNG image data URL of a given image.
137 GURL GetImageDataURL(const gfx::Image& image) {
138 if (image.IsEmpty())
139 return GURL();
140
141 scoped_refptr<base::RefCountedMemory> mem =
142 BitmapToMemory(image.ToSkBitmap());
143 std::string contents_base64;
144 if (!base::Base64Encode(
145 std::string(reinterpret_cast<const char*>(mem->front()), mem->size()),
146 &contents_base64))
147 return GURL();
148
149 const char kDataURLPrefix[] = ":image/png;base64,";
150 return GURL(std::string(chrome::kDataScheme) + kDataURLPrefix +
151 contents_base64);
152 }
153
154 // Converts the image to grayscale.
155 SkBitmap DesaturateImage(const SkBitmap* image) {
156 color_utils::HSL shift = {-1, 0, 0.6};
157 return SkBitmapOperations::CreateHSLShiftedBitmap(*image, shift);
158 }
159
160 // Creates an image from PNG data.
161 SkBitmap* ToBitmap(const unsigned char* data, size_t size) {
162 SkBitmap* decoded = new SkBitmap();
163 bool success = gfx::PNGCodec::Decode(data, size, decoded);
164 DCHECK(success);
165 return decoded;
166 }
167
168 // Load an image from a resource given its identifier |resource_id|.
169 SkBitmap* GetImageByResourceId(int resource_id) {
170 std::string contents = ResourceBundle::GetSharedInstance()
171 .GetRawDataResourceForScale(resource_id,
172 ui::SCALE_FACTOR_100P).as_string();
173
174 // Convert and return it.
175 const unsigned char* data =
176 reinterpret_cast<const unsigned char*>(contents.data());
177 return ToBitmap(data, contents.length());
178 }
179
118 } // namespace 180 } // namespace
119 181
120 namespace extensions { 182 namespace extensions {
121 183
122 //////////////////////////////////////////////////////////////////////////////// 184 ////////////////////////////////////////////////////////////////////////////////
123 // ImageLoader::ImageRepresentation 185 // ImageLoader::ImageRepresentation
124 186
125 ImageLoader::ImageRepresentation::ImageRepresentation( 187 ImageLoader::ImageRepresentation::ImageRepresentation(
126 const ExtensionResource& resource, 188 const ExtensionResource& resource,
127 ResizeCondition resize_condition, 189 ResizeCondition resize_condition,
(...skipping 30 matching lines...) Expand all
158 original_size(original_size), 220 original_size(original_size),
159 image_representation(image_representation) { 221 image_representation(image_representation) {
160 } 222 }
161 223
162 ImageLoader::LoadResult::~LoadResult() { 224 ImageLoader::LoadResult::~LoadResult() {
163 } 225 }
164 226
165 //////////////////////////////////////////////////////////////////////////////// 227 ////////////////////////////////////////////////////////////////////////////////
166 // ImageLoader 228 // ImageLoader
167 229
168 ImageLoader::ImageLoader() 230 ImageLoader::ImageLoader(Profile* profile)
169 : weak_ptr_factory_(this) { 231 : weak_ptr_factory_(this), profile_(profile) {
170 } 232 }
171 233
172 ImageLoader::~ImageLoader() { 234 ImageLoader::~ImageLoader() {
173 } 235 }
174 236
175 // static 237 // static
176 ImageLoader* ImageLoader::Get(Profile* profile) { 238 ImageLoader* ImageLoader::Get(Profile* profile) {
177 return ImageLoaderFactory::GetForProfile(profile); 239 return ImageLoaderFactory::GetForProfile(profile);
178 } 240 }
179 241
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 402
341 gfx::Image image; 403 gfx::Image image;
342 if (!image_skia.isNull()) { 404 if (!image_skia.isNull()) {
343 image_skia.MakeThreadSafe(); 405 image_skia.MakeThreadSafe();
344 image = gfx::Image(image_skia); 406 image = gfx::Image(image_skia);
345 } 407 }
346 408
347 callback.Run(image); 409 callback.Run(image);
348 } 410 }
349 411
412 void ImageLoader::LoadExtensionIconAsync(
413 const extensions::Extension* extension,
414 int icon_size,
415 bool grayscale,
416 const base::Callback<void(const gfx::Image&)>& callback) {
417 if (extension == NULL) {
418 LoadIconFailed(extension, icon_size, grayscale, callback);
419 }
Finnur 2013/09/30 15:11:21 style: Single line body, no braces needed. But un
dvh-g 2013/10/01 04:19:26 Added a comment.
420
421 ExtensionResource resource = IconsInfo::GetIconResource(
422 extension, icon_size, ExtensionIconSet::MATCH_BIGGER);
423 LoadImageAsync(extension,
424 resource,
425 gfx::Size(icon_size, icon_size),
426 base::Bind(&ImageLoader::LoadExtensionIconLoaded,
427 base::Unretained(this),
428 extension,
429 icon_size,
430 grayscale,
431 callback));
432 }
433
434 void ImageLoader::LoadExtensionIconLoaded(
435 const extensions::Extension* extension,
436 int icon_size,
437 bool grayscale,
438 const base::Callback<void(const gfx::Image&)>& callback,
439 const gfx::Image& image) {
440 if (image.IsEmpty())
441 LoadIconFailed(extension, icon_size, grayscale, callback);
442 else
443 FinalizeImage(image, grayscale, callback);
444 }
445
446 void ImageLoader::LoadIconFailed(
447 const extensions::Extension* extension,
448 int icon_size,
449 bool grayscale,
450 const base::Callback<void(const gfx::Image&)>& callback) {
451 if ((extension != NULL) &&
452 (icon_size == extension_misc::EXTENSION_ICON_BITTY))
453 LoadFaviconImage(extension, icon_size, grayscale, callback);
454 else
455 LoadDefaultImage(extension, icon_size, grayscale, callback);
456 }
457
458 void ImageLoader::LoadFaviconImage(
459 const extensions::Extension* extension,
460 int icon_size,
461 bool grayscale,
462 const base::Callback<void(const gfx::Image&)>& callback) {
463 FaviconService* favicon_service =
464 FaviconServiceFactory::GetForProfile(profile_, Profile::EXPLICIT_ACCESS);
465 // Fall back to the default icons if the service isn't available.
466 if (favicon_service == NULL) {
467 LoadDefaultImage(extension, icon_size, grayscale, callback);
468 return;
469 }
470
471 GURL favicon_url = AppLaunchInfo::GetFullLaunchURL(extension);
472 favicon_service->GetRawFaviconForURL(
473 FaviconService::FaviconForURLParams(
474 profile_, favicon_url, chrome::FAVICON, gfx::kFaviconSize),
475 ui::SCALE_FACTOR_100P,
476 base::Bind(&ImageLoader::OnFaviconDataAvailable,
477 base::Unretained(this),
478 extension,
479 icon_size,
480 grayscale,
481 callback),
482 &cancelable_task_tracker_);
483 }
484
485 void ImageLoader::OnFaviconDataAvailable(
486 const extensions::Extension* extension,
487 int icon_size,
488 bool grayscale,
489 const base::Callback<void(const gfx::Image&)>& callback,
490 const chrome::FaviconBitmapResult& bitmap_result) {
491 // Fallback to the default icon if there wasn't a favicon.
492 if (!bitmap_result.is_valid()) {
493 LoadDefaultImage(extension, icon_size, grayscale, callback);
494 return;
495 }
496
497 gfx::Image image = gfx::Image::CreateFrom1xBitmap(*ToBitmap(
498 bitmap_result.bitmap_data->front(), bitmap_result.bitmap_data->size()));
499 if (!grayscale) {
500 // If we don't need a grayscale image, then we can bypass FinalizeImage
501 // to avoid unnecessary conversions.
Finnur 2013/09/30 15:11:21 It seems we're not consistent in skipping the Fina
dvh-g 2013/10/01 04:19:26 It was the behavior of the existing code in extens
502 callback.Run(image);
503 } else {
504 FinalizeImage(image, grayscale, callback);
505 }
506 }
507
508 void ImageLoader::LoadDefaultImage(
509 const extensions::Extension* extension,
510 int icon_size,
511 bool grayscale,
512 const base::Callback<void(const gfx::Image&)>& callback) {
513 content::BrowserThread::PostTask(
514 content::BrowserThread::FILE,
515 FROM_HERE,
516 base::Bind(&ImageLoader::LoadDefaultImageOnFileThread,
517 base::Unretained(this),
518 extension,
519 icon_size,
520 grayscale,
521 callback));
522 }
523
524 void ImageLoader::LoadDefaultImageOnFileThread(
525 const extensions::Extension* extension,
526 int icon_size,
527 bool grayscale,
528 const base::Callback<void(const gfx::Image&)>& callback) {
529 const SkBitmap* default_image = NULL;
530 if ((extension == NULL) || (extension->is_app()))
531 default_image = GetDefaultAppImage();
532 else
533 default_image = GetDefaultExtensionImage();
534
535 SkBitmap result_image;
536 if (icon_size == -1) {
537 // If a specific size was not requested.
538 result_image = *default_image;
539 } else {
540 SkBitmap resized_image(
541 skia::ImageOperations::Resize(*default_image,
542 skia::ImageOperations::RESIZE_LANCZOS3,
543 icon_size,
544 icon_size));
545 // There are cases where Resize returns an empty bitmap, for example if you
546 // ask for an image too large. In this case it is better to return the
547 // default image than returning nothing at all.
548 if (resized_image.empty())
549 resized_image = *default_image;
550 result_image = resized_image;
551 }
552
553 content::BrowserThread::PostTask(
554 content::BrowserThread::UI,
555 FROM_HERE,
556 base::Bind(&ImageLoader::LoadDefaultImageDone,
557 base::Unretained(this),
558 gfx::Image::CreateFrom1xBitmap(result_image),
559 grayscale,
560 callback));
561 }
562
563 void ImageLoader::LoadDefaultImageDone(
564 const gfx::Image& image,
565 bool grayscale,
566 const base::Callback<void(const gfx::Image&)>& callback) {
567 FinalizeImage(image, grayscale, callback);
568 }
569
570 void ImageLoader::FinalizeImage(
571 const gfx::Image& image,
572 bool grayscale,
573 const base::Callback<void(const gfx::Image&)>& callback) {
574 content::BrowserThread::PostTask(
575 content::BrowserThread::FILE,
576 FROM_HERE,
577 base::Bind(&ImageLoader::FinalizeImageOnFileThread,
578 base::Unretained(this),
579 image,
580 grayscale,
581 callback));
582 }
583
584 void ImageLoader::FinalizeImageOnFileThread(
585 const gfx::Image& image,
586 bool grayscale,
587 const base::Callback<void(const gfx::Image&)>& callback) {
588 SkBitmap bitmap;
589 if (grayscale)
590 bitmap = DesaturateImage(image.ToSkBitmap());
591 else
592 bitmap = *image.ToSkBitmap();
593
594 gfx::Image modifiedImage = gfx::Image::CreateFrom1xBitmap(bitmap);
595 content::BrowserThread::PostTask(content::BrowserThread::UI,
596 FROM_HERE,
597 base::Bind(&ImageLoader::FinalizeImageDone,
598 base::Unretained(this),
599 modifiedImage,
600 callback));
601 }
602
603 void ImageLoader::FinalizeImageDone(
604 const gfx::Image& image,
605 const base::Callback<void(const gfx::Image&)>& callback) {
606 callback.Run(image);
607 }
608
609 void ImageLoader::LoadExtensionIconDataURLAsync(
610 const extensions::Extension* extension,
611 int icon_size,
612 bool grayscale,
613 const base::Callback<void(const GURL&)>& callback) {
614 LoadExtensionIconAsync(extension,
615 icon_size,
616 grayscale,
617 base::Bind(&ImageLoader::OnIconAvailable,
618 base::Unretained(this),
619 callback));
620 }
621
622 void ImageLoader::OnIconAvailable(
623 const base::Callback<void(const GURL&)>& callback,
624 const gfx::Image& image) {
625 content::BrowserThread::PostTask(
626 content::BrowserThread::FILE,
627 FROM_HERE,
628 base::Bind(&ImageLoader::ConvertIconToURLOnFileThread,
629 base::Unretained(this),
630 image,
631 callback));
632 }
633
634 void ImageLoader::ConvertIconToURLOnFileThread(
635 const gfx::Image& image,
636 const base::Callback<void(const GURL&)>& callback) {
637 GURL url = GetImageDataURL(image);
638 content::BrowserThread::PostTask(
639 content::BrowserThread::UI,
640 FROM_HERE,
641 base::Bind(&ImageLoader::OnIconConvertedToURL,
642 base::Unretained(this),
643 url,
644 callback));
645 }
646
647 void ImageLoader::OnIconConvertedToURL(
648 const GURL& url,
649 const base::Callback<void(const GURL&)>& callback) {
650 callback.Run(url);
651 }
652
653 const SkBitmap* ImageLoader::GetDefaultAppImage() {
654 if (!default_app_data_.get())
655 default_app_data_.reset(GetImageByResourceId(IDR_APP_DEFAULT_ICON));
656
657 return default_app_data_.get();
658 }
659
660 const SkBitmap* ImageLoader::GetDefaultExtensionImage() {
661 if (!default_extension_data_.get()) {
662 default_extension_data_.reset(
663 GetImageByResourceId(IDR_EXTENSION_DEFAULT_ICON));
664 }
665
666 return default_extension_data_.get();
667 }
668
350 } // namespace extensions 669 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698