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

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 // Returns a PNG image data URL of a given image.
130 GURL GetImageDataURL(const gfx::Image& image) {
131 if (image.IsEmpty())
132 return GURL();
133
134 scoped_refptr<base::RefCountedMemory> mem =
135 ImageLoader::BitmapToMemory(image.ToSkBitmap());
136 std::string contents_base64;
137 if (!base::Base64Encode(
138 std::string(reinterpret_cast<const char*>(mem->front()), mem->size()),
139 &contents_base64))
140 return GURL();
141
142 const char kDataURLPrefix[] = ":image/png;base64,";
143 return GURL(std::string(chrome::kDataScheme) + kDataURLPrefix +
144 contents_base64);
145 }
146
147 // Converts the image to grayscale.
148 SkBitmap DesaturateImage(const SkBitmap* image) {
149 color_utils::HSL shift = {-1, 0, 0.6};
150 return SkBitmapOperations::CreateHSLShiftedBitmap(*image, shift);
151 }
152
153 // Creates an image from PNG data.
154 SkBitmap* ToBitmap(const unsigned char* data, size_t size) {
155 SkBitmap* decoded = new SkBitmap();
156 bool success = gfx::PNGCodec::Decode(data, size, decoded);
157 DCHECK(success);
158 return decoded;
159 }
160
161 // Load an image from a resource given its identifier |resource_id|.
162 SkBitmap* GetImageByResourceId(int resource_id) {
163 std::string contents = ResourceBundle::GetSharedInstance()
164 .GetRawDataResourceForScale(resource_id,
165 ui::SCALE_FACTOR_100P).as_string();
166
167 // Convert and return it.
168 const unsigned char* data =
169 reinterpret_cast<const unsigned char*>(contents.data());
170 return ToBitmap(data, contents.length());
171 }
172
118 } // namespace 173 } // namespace
119 174
120 namespace extensions { 175 namespace extensions {
121 176
122 //////////////////////////////////////////////////////////////////////////////// 177 ////////////////////////////////////////////////////////////////////////////////
123 // ImageLoader::ImageRepresentation 178 // ImageLoader::ImageRepresentation
124 179
125 ImageLoader::ImageRepresentation::ImageRepresentation( 180 ImageLoader::ImageRepresentation::ImageRepresentation(
126 const ExtensionResource& resource, 181 const ExtensionResource& resource,
127 ResizeCondition resize_condition, 182 ResizeCondition resize_condition,
(...skipping 30 matching lines...) Expand all
158 original_size(original_size), 213 original_size(original_size),
159 image_representation(image_representation) { 214 image_representation(image_representation) {
160 } 215 }
161 216
162 ImageLoader::LoadResult::~LoadResult() { 217 ImageLoader::LoadResult::~LoadResult() {
163 } 218 }
164 219
165 //////////////////////////////////////////////////////////////////////////////// 220 ////////////////////////////////////////////////////////////////////////////////
166 // ImageLoader 221 // ImageLoader
167 222
168 ImageLoader::ImageLoader() 223 ImageLoader::ImageLoader(Profile* profile)
169 : weak_ptr_factory_(this) { 224 : weak_ptr_factory_(this), profile_(profile) {
170 } 225 }
171 226
172 ImageLoader::~ImageLoader() { 227 ImageLoader::~ImageLoader() {
173 } 228 }
174 229
175 // static 230 // static
176 ImageLoader* ImageLoader::Get(Profile* profile) { 231 ImageLoader* ImageLoader::Get(Profile* profile) {
177 return ImageLoaderFactory::GetForProfile(profile); 232 return ImageLoaderFactory::GetForProfile(profile);
178 } 233 }
179 234
(...skipping 160 matching lines...) Expand 10 before | Expand all | Expand 10 after
340 395
341 gfx::Image image; 396 gfx::Image image;
342 if (!image_skia.isNull()) { 397 if (!image_skia.isNull()) {
343 image_skia.MakeThreadSafe(); 398 image_skia.MakeThreadSafe();
344 image = gfx::Image(image_skia); 399 image = gfx::Image(image_skia);
345 } 400 }
346 401
347 callback.Run(image); 402 callback.Run(image);
348 } 403 }
349 404
405 void ImageLoader::LoadExtensionIconAsync(
406 const extensions::Extension* extension,
407 int icon_size,
408 ExtensionIconSet::MatchType match,
409 bool grayscale,
410 const base::Callback<void(const gfx::Image&)>& callback) {
411 // |extension| can be NULL when the default icon is requested. In this case,
412 // fail the icon loading, which will result in the default icon being loaded.
413 if (extension == NULL) {
414 LoadIconFailed(extension, icon_size, grayscale, callback);
415 return;
416 }
417
418 ExtensionResource resource = IconsInfo::GetIconResource(
419 extension, icon_size, match);
420 LoadImageAsync(extension,
421 resource,
422 gfx::Size(icon_size, icon_size),
423 base::Bind(&ImageLoader::LoadExtensionIconDone,
424 base::Unretained(this),
425 extension,
426 icon_size,
427 grayscale,
428 callback));
429 }
430
431 void ImageLoader::LoadExtensionIconDone(
432 const extensions::Extension* extension,
433 int icon_size,
434 bool grayscale,
435 const base::Callback<void(const gfx::Image&)>& callback,
436 const gfx::Image& image) {
437 if (image.IsEmpty())
438 LoadIconFailed(extension, icon_size, grayscale, callback);
439 else
440 FinalizeImage(image, grayscale, callback);
441 }
442
443 void ImageLoader::LoadIconFailed(
444 const extensions::Extension* extension,
445 int icon_size,
446 bool grayscale,
447 const base::Callback<void(const gfx::Image&)>& callback) {
448 if ((extension != NULL) &&
449 (icon_size == extension_misc::EXTENSION_ICON_BITTY))
450 LoadFaviconImage(extension, icon_size, grayscale, callback);
451 else
452 LoadDefaultImage(extension, icon_size, grayscale, callback);
453 }
454
455 void ImageLoader::LoadFaviconImage(
456 const extensions::Extension* extension,
457 int icon_size,
458 bool grayscale,
459 const base::Callback<void(const gfx::Image&)>& callback) {
460 FaviconService* favicon_service = NULL;
461 if (profile_ != NULL)
462 favicon_service = FaviconServiceFactory::GetForProfile(
463 profile_, Profile::EXPLICIT_ACCESS);
464 // Fall back to the default icons if the service isn't available.
465 if (favicon_service == NULL) {
466 LoadDefaultImage(extension, icon_size, grayscale, callback);
467 return;
468 }
469
470 GURL favicon_url = AppLaunchInfo::GetFullLaunchURL(extension);
471 favicon_service->GetRawFaviconForURL(
472 FaviconService::FaviconForURLParams(
473 profile_, favicon_url, chrome::FAVICON, gfx::kFaviconSize),
474 ui::SCALE_FACTOR_100P,
475 base::Bind(&ImageLoader::OnFaviconDataAvailable,
476 base::Unretained(this),
477 extension,
478 icon_size,
479 grayscale,
480 callback),
481 &cancelable_task_tracker_);
482 }
483
484 void ImageLoader::OnFaviconDataAvailable(
485 const extensions::Extension* extension,
486 int icon_size,
487 bool grayscale,
488 const base::Callback<void(const gfx::Image&)>& callback,
489 const chrome::FaviconBitmapResult& bitmap_result) {
490 // Fallback to the default icon if there wasn't a favicon.
491 if (!bitmap_result.is_valid()) {
492 LoadDefaultImage(extension, icon_size, grayscale, callback);
493 return;
494 }
495
496 gfx::Image image = gfx::Image::CreateFrom1xBitmap(*ToBitmap(
497 bitmap_result.bitmap_data->front(), bitmap_result.bitmap_data->size()));
498 FinalizeImage(image, grayscale, callback);
499 }
500
501 void ImageLoader::LoadDefaultImage(
502 const extensions::Extension* extension,
503 int icon_size,
504 bool grayscale,
505 const base::Callback<void(const gfx::Image&)>& callback) {
506 content::BrowserThread::PostTask(
507 content::BrowserThread::FILE,
508 FROM_HERE,
509 base::Bind(&ImageLoader::LoadDefaultImageOnFileThread,
510 base::Unretained(this),
511 extension,
512 icon_size,
513 grayscale,
514 callback));
515 }
516
517 void ImageLoader::LoadDefaultImageOnFileThread(
518 const extensions::Extension* extension,
519 int icon_size,
520 bool grayscale,
521 const base::Callback<void(const gfx::Image&)>& callback) {
522 const SkBitmap* default_image = NULL;
523 if ((extension == NULL) || (extension->is_app()))
524 default_image = GetDefaultAppImage();
525 else
526 default_image = GetDefaultExtensionImage();
527
528 SkBitmap result_image;
529 if (icon_size == -1) {
530 // If a specific size was not requested.
531 result_image = *default_image;
532 } else {
533 SkBitmap resized_image(
534 skia::ImageOperations::Resize(*default_image,
535 skia::ImageOperations::RESIZE_LANCZOS3,
536 icon_size,
537 icon_size));
538 // There are cases where Resize returns an empty bitmap, for example if you
539 // ask for an image too large. In this case it is better to return the
540 // default image than returning nothing at all.
541 if (resized_image.empty())
542 resized_image = *default_image;
543 result_image = resized_image;
544 }
545
546 content::BrowserThread::PostTask(
547 content::BrowserThread::UI,
548 FROM_HERE,
549 base::Bind(&ImageLoader::LoadDefaultImageDone,
550 base::Unretained(this),
551 gfx::Image::CreateFrom1xBitmap(result_image),
552 grayscale,
553 callback));
554 }
555
556 void ImageLoader::LoadDefaultImageDone(
557 const gfx::Image& image,
558 bool grayscale,
559 const base::Callback<void(const gfx::Image&)>& callback) {
560 FinalizeImage(image, grayscale, callback);
561 }
562
563 void ImageLoader::FinalizeImage(
564 const gfx::Image& image,
565 bool grayscale,
566 const base::Callback<void(const gfx::Image&)>& callback) {
567 content::BrowserThread::PostTask(
568 content::BrowserThread::FILE,
569 FROM_HERE,
570 base::Bind(&ImageLoader::FinalizeImageOnFileThread,
571 base::Unretained(this),
572 image,
573 grayscale,
574 callback));
575 }
576
577 void ImageLoader::FinalizeImageOnFileThread(
578 const gfx::Image& image,
579 bool grayscale,
580 const base::Callback<void(const gfx::Image&)>& callback) {
581 SkBitmap bitmap;
582 if (grayscale)
583 bitmap = DesaturateImage(image.ToSkBitmap());
584 else
585 bitmap = *image.ToSkBitmap();
586
587 gfx::Image modifiedImage = gfx::Image::CreateFrom1xBitmap(bitmap);
588 content::BrowserThread::PostTask(content::BrowserThread::UI,
589 FROM_HERE,
590 base::Bind(&ImageLoader::FinalizeImageDone,
591 base::Unretained(this),
592 modifiedImage,
593 callback));
594 }
595
596 void ImageLoader::FinalizeImageDone(
597 const gfx::Image& image,
598 const base::Callback<void(const gfx::Image&)>& callback) {
599 callback.Run(image);
600 }
601
602 void ImageLoader::LoadExtensionIconDataURLAsync(
603 const extensions::Extension* extension,
604 int icon_size,
605 ExtensionIconSet::MatchType match,
606 bool grayscale,
607 const base::Callback<void(const GURL&)>& callback) {
608 LoadExtensionIconAsync(extension,
609 icon_size,
610 match,
611 grayscale,
612 base::Bind(&ImageLoader::OnIconAvailable,
613 base::Unretained(this),
614 callback));
615 }
616
617 void ImageLoader::OnIconAvailable(
618 const base::Callback<void(const GURL&)>& callback,
619 const gfx::Image& image) {
620 content::BrowserThread::PostTask(
621 content::BrowserThread::FILE,
622 FROM_HERE,
623 base::Bind(&ImageLoader::ConvertIconToURLOnFileThread,
624 base::Unretained(this),
625 image,
626 callback));
627 }
628
629 void ImageLoader::ConvertIconToURLOnFileThread(
630 const gfx::Image& image,
631 const base::Callback<void(const GURL&)>& callback) {
632 GURL url = GetImageDataURL(image);
633 content::BrowserThread::PostTask(
634 content::BrowserThread::UI,
635 FROM_HERE,
636 base::Bind(&ImageLoader::OnIconConvertedToURL,
637 base::Unretained(this),
638 url,
639 callback));
640 }
641
642 void ImageLoader::OnIconConvertedToURL(
643 const GURL& url,
644 const base::Callback<void(const GURL&)>& callback) {
645 callback.Run(url);
646 }
647
648 const SkBitmap* ImageLoader::GetDefaultAppImage() {
649 if (!default_app_icon_.get())
650 default_app_icon_.reset(GetImageByResourceId(IDR_APP_DEFAULT_ICON));
651
652 return default_app_icon_.get();
653 }
654
655 const SkBitmap* ImageLoader::GetDefaultExtensionImage() {
656 if (!default_extension_icon_.get()) {
657 default_extension_icon_.reset(
658 GetImageByResourceId(IDR_EXTENSION_DEFAULT_ICON));
659 }
660
661 return default_extension_icon_.get();
662 }
663
664 scoped_refptr<base::RefCountedMemory> ImageLoader::BitmapToMemory(
665 const SkBitmap* image) {
666 base::RefCountedBytes* image_bytes = new base::RefCountedBytes;
667 gfx::PNGCodec::EncodeBGRASkBitmap(*image, false, &image_bytes->data());
668 return image_bytes;
669 }
670
350 } // namespace extensions 671 } // namespace extensions
OLDNEW
« no previous file with comments | « chrome/browser/extensions/image_loader.h ('k') | chrome/browser/extensions/image_loader_factory.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698