1 // Copyright (c) 2010 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/extension_icon_manager.h"
6
7 #include "base/logging.h"
8 #include "base/stl_util-inl.h"
9 #include "chrome/common/extensions/extension.h"
10 #include "chrome/common/extensions/extension_icon_set.h"
11 #include "chrome/common/extensions/extension_resource.h"
12 #include "grit/theme_resources.h"
13 #include "skia/ext/image_operations.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/canvas_skia.h"
16 #include "ui/gfx/color_utils.h"
17 #include "ui/gfx/favicon_size.h"
18 #include "ui/gfx/size.h"
19 #include "ui/gfx/skbitmap_operations.h"
20
21 namespace {
22
23 // Helper function to create a new bitmap with |padding| amount of empty space
24 // around the original bitmap.
ApplyPadding(const SkBitmap & source,const gfx::Insets & padding)25 static SkBitmap ApplyPadding(const SkBitmap& source,
26 const gfx::Insets& padding) {
27 scoped_ptr<gfx::CanvasSkia> result(
28 new gfx::CanvasSkia(source.width() + padding.width(),
29 source.height() + padding.height(), false));
30 result->DrawBitmapInt(
31 source,
32 0, 0, source.width(), source.height(),
33 padding.left(), padding.top(), source.width(), source.height(),
34 false);
35 return result->ExtractBitmap();
36 }
37
38 } // namespace
39
ExtensionIconManager()40 ExtensionIconManager::ExtensionIconManager()
41 : ALLOW_THIS_IN_INITIALIZER_LIST(image_tracker_(this)),
42 monochrome_(false) {
43 }
44
~ExtensionIconManager()45 ExtensionIconManager::~ExtensionIconManager() {
46 }
47
LoadIcon(const Extension * extension)48 void ExtensionIconManager::LoadIcon(const Extension* extension) {
49 ExtensionResource icon_resource = extension->GetIconResource(
50 Extension::EXTENSION_ICON_BITTY, ExtensionIconSet::MATCH_BIGGER);
51 if (!icon_resource.extension_root().empty()) {
52 // Insert into pending_icons_ first because LoadImage can call us back
53 // synchronously if the image is already cached.
54 pending_icons_.insert(extension->id());
55 image_tracker_.LoadImage(extension,
56 icon_resource,
57 gfx::Size(kFaviconSize, kFaviconSize),
58 ImageLoadingTracker::CACHE);
59 }
60 }
61
GetIcon(const std::string & extension_id)62 const SkBitmap& ExtensionIconManager::GetIcon(const std::string& extension_id) {
63 const SkBitmap* result = NULL;
64 if (ContainsKey(icons_, extension_id)) {
65 result = &icons_[extension_id];
66 } else {
67 EnsureDefaultIcon();
68 result = &default_icon_;
69 }
70 DCHECK(result);
71 DCHECK_EQ(kFaviconSize + padding_.width(), result->width());
72 DCHECK_EQ(kFaviconSize + padding_.height(), result->height());
73 return *result;
74 }
75
RemoveIcon(const std::string & extension_id)76 void ExtensionIconManager::RemoveIcon(const std::string& extension_id) {
77 icons_.erase(extension_id);
78 pending_icons_.erase(extension_id);
79 }
80
OnImageLoaded(SkBitmap * image,const ExtensionResource & resource,int index)81 void ExtensionIconManager::OnImageLoaded(SkBitmap* image,
82 const ExtensionResource& resource,
83 int index) {
84 if (!image)
85 return;
86
87 const std::string extension_id = resource.extension_id();
88
89 // We may have removed the icon while waiting for it to load. In that case,
90 // do nothing.
91 if (!ContainsKey(pending_icons_, extension_id))
92 return;
93
94 pending_icons_.erase(extension_id);
95 icons_[extension_id] = ApplyTransforms(*image);
96 }
97
EnsureDefaultIcon()98 void ExtensionIconManager::EnsureDefaultIcon() {
99 if (default_icon_.empty()) {
100 ResourceBundle& rb = ResourceBundle::GetSharedInstance();
101 SkBitmap* src = rb.GetBitmapNamed(IDR_EXTENSIONS_SECTION);
102 default_icon_ = ApplyTransforms(*src);
103 }
104 }
105
ApplyTransforms(const SkBitmap & source)106 SkBitmap ExtensionIconManager::ApplyTransforms(const SkBitmap& source) {
107 SkBitmap result = source;
108
109 if (result.width() != kFaviconSize || result.height() != kFaviconSize) {
110 result = skia::ImageOperations::Resize(
111 result, skia::ImageOperations::RESIZE_LANCZOS3,
112 kFaviconSize, kFaviconSize);
113 }
114
115 if (monochrome_) {
116 color_utils::HSL shift = {-1, 0, 0.6};
117 result = SkBitmapOperations::CreateHSLShiftedBitmap(result, shift);
118 }
119
120 if (!padding_.empty())
121 result = ApplyPadding(result, padding_);
122
123 return result;
124 }
125