OLD | NEW |
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/extension_action.h" | 5 #include "chrome/browser/extensions/extension_action.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "base/base64.h" | 9 #include "base/base64.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
| 11 #include "base/strings/string_number_conversions.h" |
11 #include "extensions/browser/extension_icon_image.h" | 12 #include "extensions/browser/extension_icon_image.h" |
12 #include "extensions/browser/extension_icon_placeholder.h" | 13 #include "extensions/browser/extension_icon_placeholder.h" |
13 #include "extensions/common/constants.h" | 14 #include "extensions/common/constants.h" |
14 #include "extensions/common/extension_icon_set.h" | 15 #include "extensions/common/extension_icon_set.h" |
15 #include "extensions/common/feature_switch.h" | 16 #include "extensions/common/feature_switch.h" |
16 #include "extensions/common/manifest_handlers/icons_handler.h" | 17 #include "extensions/common/manifest_handlers/icons_handler.h" |
17 #include "grit/theme_resources.h" | 18 #include "grit/theme_resources.h" |
18 #include "grit/ui_resources.h" | 19 #include "grit/ui_resources.h" |
19 #include "ipc/ipc_message.h" | 20 #include "ipc/ipc_message.h" |
20 #include "ipc/ipc_message_utils.h" | 21 #include "ipc/ipc_message_utils.h" |
21 #include "third_party/skia/include/core/SkBitmap.h" | 22 #include "third_party/skia/include/core/SkBitmap.h" |
22 #include "third_party/skia/include/core/SkCanvas.h" | 23 #include "third_party/skia/include/core/SkCanvas.h" |
23 #include "third_party/skia/include/core/SkPaint.h" | 24 #include "third_party/skia/include/core/SkPaint.h" |
24 #include "third_party/skia/include/effects/SkGradientShader.h" | 25 #include "third_party/skia/include/effects/SkGradientShader.h" |
| 26 #include "ui/base/resource/material_design/material_design_controller.h" |
25 #include "ui/base/resource/resource_bundle.h" | 27 #include "ui/base/resource/resource_bundle.h" |
26 #include "ui/gfx/animation/animation_delegate.h" | 28 #include "ui/gfx/animation/animation_delegate.h" |
27 #include "ui/gfx/canvas.h" | 29 #include "ui/gfx/canvas.h" |
28 #include "ui/gfx/color_utils.h" | 30 #include "ui/gfx/color_utils.h" |
29 #include "ui/gfx/geometry/rect.h" | 31 #include "ui/gfx/geometry/rect.h" |
30 #include "ui/gfx/geometry/size.h" | 32 #include "ui/gfx/geometry/size.h" |
31 #include "ui/gfx/image/image.h" | 33 #include "ui/gfx/image/image.h" |
32 #include "ui/gfx/image/image_skia.h" | 34 #include "ui/gfx/image/image_skia.h" |
33 #include "ui/gfx/image/image_skia_source.h" | 35 #include "ui/gfx/image/image_skia_source.h" |
34 #include "ui/gfx/ipc/gfx_param_traits.h" | 36 #include "ui/gfx/ipc/gfx_param_traits.h" |
35 #include "ui/gfx/skbitmap_operations.h" | 37 #include "ui/gfx/skbitmap_operations.h" |
36 #include "url/gurl.h" | 38 #include "url/gurl.h" |
37 | 39 |
38 namespace { | 40 namespace { |
39 | 41 |
40 // Returns the default icon image for extensions. | 42 // Returns the default icon image for extensions. |
41 gfx::Image GetDefaultIcon() { | 43 gfx::Image GetDefaultIcon() { |
42 return ui::ResourceBundle::GetSharedInstance().GetImageNamed( | 44 return ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
43 IDR_EXTENSIONS_FAVICON); | 45 IDR_EXTENSIONS_FAVICON); |
44 } | 46 } |
45 | 47 |
46 // Given the extension action type, returns the size the extension action icon | |
47 // should have. The icon should be square, so only one dimension is | |
48 // returned. | |
49 int GetIconSizeForType(extensions::ActionInfo::Type type) { | |
50 switch (type) { | |
51 case extensions::ActionInfo::TYPE_BROWSER: | |
52 case extensions::ActionInfo::TYPE_PAGE: | |
53 case extensions::ActionInfo::TYPE_SYSTEM_INDICATOR: | |
54 // TODO(dewittj) Report the actual icon size of the system | |
55 // indicator. | |
56 return extension_misc::EXTENSION_ICON_ACTION; | |
57 default: | |
58 NOTREACHED(); | |
59 return 0; | |
60 } | |
61 } | |
62 | |
63 class GetAttentionImageSource : public gfx::ImageSkiaSource { | 48 class GetAttentionImageSource : public gfx::ImageSkiaSource { |
64 public: | 49 public: |
65 explicit GetAttentionImageSource(const gfx::ImageSkia& icon) | 50 explicit GetAttentionImageSource(const gfx::ImageSkia& icon) |
66 : icon_(icon) {} | 51 : icon_(icon) {} |
67 | 52 |
68 // gfx::ImageSkiaSource overrides: | 53 // gfx::ImageSkiaSource overrides: |
69 gfx::ImageSkiaRep GetImageForScale(float scale) override { | 54 gfx::ImageSkiaRep GetImageForScale(float scale) override { |
70 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale); | 55 gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale); |
71 color_utils::HSL shift = {-1, 0, 0.5}; | 56 color_utils::HSL shift = {-1, 0, 0.5}; |
72 return gfx::ImageSkiaRep( | 57 return gfx::ImageSkiaRep( |
73 SkBitmapOperations::CreateHSLShiftedBitmap(icon_rep.sk_bitmap(), shift), | 58 SkBitmapOperations::CreateHSLShiftedBitmap(icon_rep.sk_bitmap(), shift), |
74 icon_rep.scale()); | 59 icon_rep.scale()); |
75 } | 60 } |
76 | 61 |
77 private: | 62 private: |
78 const gfx::ImageSkia icon_; | 63 const gfx::ImageSkia icon_; |
79 }; | 64 }; |
80 | 65 |
81 struct IconRepresentationInfo { | 66 struct IconRepresentationInfo { |
82 // Size as a string that will be used to retrieve a representation value from | 67 // Size as a string that will be used to retrieve a representation value from |
83 // SetIcon function arguments. | 68 // SetIcon function arguments. |
84 const char* size_string; | 69 const char* size_string; |
85 // Scale factor for which the represantion should be used. | 70 // Scale factor for which the represantion should be used. |
86 ui::ScaleFactor scale; | 71 ui::ScaleFactor scale; |
87 }; | 72 }; |
88 | 73 |
89 const IconRepresentationInfo kIconSizes[] = {{"19", ui::SCALE_FACTOR_100P}, | |
90 {"38", ui::SCALE_FACTOR_200P}}; | |
91 | |
92 template <class T> | 74 template <class T> |
93 bool HasValue(const std::map<int, T>& map, int tab_id) { | 75 bool HasValue(const std::map<int, T>& map, int tab_id) { |
94 return map.find(tab_id) != map.end(); | 76 return map.find(tab_id) != map.end(); |
95 } | 77 } |
96 | 78 |
97 } // namespace | 79 } // namespace |
98 | 80 |
| 81 extension_misc::ExtensionIcons ExtensionAction::ActionIconSize() { |
| 82 return ui::MaterialDesignController::IsModeMaterial() |
| 83 ? extension_misc::EXTENSION_ICON_BITTY |
| 84 : extension_misc::EXTENSION_ICON_ACTION; |
| 85 } |
| 86 |
99 const int ExtensionAction::kDefaultTabId = -1; | 87 const int ExtensionAction::kDefaultTabId = -1; |
100 const int ExtensionAction::kPageActionIconMaxSize = | |
101 extension_misc::EXTENSION_ICON_ACTION; | |
102 | 88 |
103 ExtensionAction::ExtensionAction(const extensions::Extension& extension, | 89 ExtensionAction::ExtensionAction(const extensions::Extension& extension, |
104 extensions::ActionInfo::Type action_type, | 90 extensions::ActionInfo::Type action_type, |
105 const extensions::ActionInfo& manifest_data) | 91 const extensions::ActionInfo& manifest_data) |
106 : extension_id_(extension.id()), | 92 : extension_id_(extension.id()), |
107 extension_name_(extension.name()), | 93 extension_name_(extension.name()), |
108 action_type_(action_type) { | 94 action_type_(action_type) { |
109 // Page/script actions are hidden/disabled by default, and browser actions are | 95 // Page/script actions are hidden/disabled by default, and browser actions are |
110 // visible/enabled by default. | 96 // visible/enabled by default. |
111 SetIsVisible(kDefaultTabId, | 97 SetIsVisible(kDefaultTabId, |
(...skipping 21 matching lines...) Expand all Loading... |
133 return GetValue(&popup_url_, tab_id); | 119 return GetValue(&popup_url_, tab_id); |
134 } | 120 } |
135 | 121 |
136 void ExtensionAction::SetIcon(int tab_id, const gfx::Image& image) { | 122 void ExtensionAction::SetIcon(int tab_id, const gfx::Image& image) { |
137 SetValue(&icon_, tab_id, image); | 123 SetValue(&icon_, tab_id, image); |
138 } | 124 } |
139 | 125 |
140 bool ExtensionAction::ParseIconFromCanvasDictionary( | 126 bool ExtensionAction::ParseIconFromCanvasDictionary( |
141 const base::DictionaryValue& dict, | 127 const base::DictionaryValue& dict, |
142 gfx::ImageSkia* icon) { | 128 gfx::ImageSkia* icon) { |
143 // Try to extract an icon for each known scale. | 129 for (base::DictionaryValue::Iterator iter(dict); !iter.IsAtEnd(); |
144 for (size_t i = 0; i < arraysize(kIconSizes); i++) { | 130 iter.Advance()) { |
| 131 int icon_size = 0; |
| 132 if (!base::StringToInt(iter.key(), &icon_size)) |
| 133 continue; |
| 134 |
145 const base::BinaryValue* image_data; | 135 const base::BinaryValue* image_data; |
146 std::string binary_string64; | 136 std::string binary_string64; |
147 IPC::Message pickle; | 137 IPC::Message pickle; |
148 if (dict.GetBinary(kIconSizes[i].size_string, &image_data)) { | 138 if (iter.value().GetAsBinary(&image_data)) { |
149 pickle = IPC::Message(image_data->GetBuffer(), image_data->GetSize()); | 139 pickle = IPC::Message(image_data->GetBuffer(), image_data->GetSize()); |
150 } else if (dict.GetString(kIconSizes[i].size_string, &binary_string64)) { | 140 } else if (iter.value().GetAsString(&binary_string64)) { |
151 std::string binary_string; | 141 std::string binary_string; |
152 if (!base::Base64Decode(binary_string64, &binary_string)) | 142 if (!base::Base64Decode(binary_string64, &binary_string)) |
153 return false; | 143 return false; |
154 pickle = IPC::Message(binary_string.c_str(), binary_string.length()); | 144 pickle = IPC::Message(binary_string.c_str(), binary_string.length()); |
155 } else { | 145 } else { |
156 continue; | 146 continue; |
157 } | 147 } |
158 base::PickleIterator iter(pickle); | 148 base::PickleIterator pickle_iter(pickle); |
159 SkBitmap bitmap; | 149 SkBitmap bitmap; |
160 if (!IPC::ReadParam(&pickle, &iter, &bitmap)) | 150 if (!IPC::ReadParam(&pickle, &pickle_iter, &bitmap)) |
161 return false; | 151 return false; |
162 CHECK(!bitmap.isNull()); | 152 CHECK(!bitmap.isNull()); |
163 float scale = ui::GetScaleForScaleFactor(kIconSizes[i].scale); | 153 float scale = |
| 154 static_cast<float>(icon_size) / ExtensionAction::ActionIconSize(); |
164 icon->AddRepresentation(gfx::ImageSkiaRep(bitmap, scale)); | 155 icon->AddRepresentation(gfx::ImageSkiaRep(bitmap, scale)); |
165 } | 156 } |
166 return true; | 157 return true; |
167 } | 158 } |
168 | 159 |
169 gfx::Image ExtensionAction::GetExplicitlySetIcon(int tab_id) const { | 160 gfx::Image ExtensionAction::GetExplicitlySetIcon(int tab_id) const { |
170 return GetValue(&icon_, tab_id); | 161 return GetValue(&icon_, tab_id); |
171 } | 162 } |
172 | 163 |
173 bool ExtensionAction::SetIsVisible(int tab_id, bool new_visibility) { | 164 bool ExtensionAction::SetIsVisible(int tab_id, bool new_visibility) { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 // when the tab's closed. There's a race between the | 224 // when the tab's closed. There's a race between the |
234 // LocationBarController and the ContentRulesRegistry on navigation, | 225 // LocationBarController and the ContentRulesRegistry on navigation, |
235 // which prevents me from cleaning everything up now. | 226 // which prevents me from cleaning everything up now. |
236 } | 227 } |
237 | 228 |
238 extensions::IconImage* ExtensionAction::LoadDefaultIconImage( | 229 extensions::IconImage* ExtensionAction::LoadDefaultIconImage( |
239 const extensions::Extension& extension, | 230 const extensions::Extension& extension, |
240 content::BrowserContext* browser_context) { | 231 content::BrowserContext* browser_context) { |
241 if (default_icon_ && !default_icon_image_) { | 232 if (default_icon_ && !default_icon_image_) { |
242 default_icon_image_.reset(new extensions::IconImage( | 233 default_icon_image_.reset(new extensions::IconImage( |
243 browser_context, | 234 browser_context, &extension, *default_icon(), ActionIconSize(), |
244 &extension, | 235 *GetDefaultIcon().ToImageSkia(), nullptr)); |
245 *default_icon(), | |
246 GetIconSizeForType(action_type_), | |
247 *GetDefaultIcon().ToImageSkia(), | |
248 nullptr)); | |
249 } | 236 } |
250 return default_icon_image_.get(); | 237 return default_icon_image_.get(); |
251 } | 238 } |
252 | 239 |
253 gfx::Image ExtensionAction::GetDefaultIconImage() const { | 240 gfx::Image ExtensionAction::GetDefaultIconImage() const { |
254 // If we have a default icon, it should be loaded before trying to use it. | 241 // If we have a default icon, it should be loaded before trying to use it. |
255 DCHECK(!default_icon_image_ == !default_icon_); | 242 DCHECK(!default_icon_image_ == !default_icon_); |
256 if (default_icon_image_) | 243 if (default_icon_image_) |
257 return default_icon_image_->image(); | 244 return default_icon_image_->image(); |
258 | 245 |
259 if (placeholder_icon_image_.IsEmpty()) { | 246 if (placeholder_icon_image_.IsEmpty()) { |
260 // If the extension action redesign is enabled, we use a special placeholder | 247 // If the extension action redesign is enabled, we use a special placeholder |
261 // icon (with the first letter of the extension name) rather than the | 248 // icon (with the first letter of the extension name) rather than the |
262 // default (puzzle piece). | 249 // default (puzzle piece). |
263 if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) { | 250 if (extensions::FeatureSwitch::extension_action_redesign()->IsEnabled()) { |
264 placeholder_icon_image_ = | 251 placeholder_icon_image_ = |
265 extensions::ExtensionIconPlaceholder::CreateImage( | 252 extensions::ExtensionIconPlaceholder::CreateImage(ActionIconSize(), |
266 extension_misc::EXTENSION_ICON_ACTION, extension_name_); | 253 extension_name_); |
267 } else { | 254 } else { |
268 placeholder_icon_image_ = GetDefaultIcon(); | 255 placeholder_icon_image_ = GetDefaultIcon(); |
269 } | 256 } |
270 } | 257 } |
271 | 258 |
272 return placeholder_icon_image_; | 259 return placeholder_icon_image_; |
273 } | 260 } |
274 | 261 |
275 bool ExtensionAction::HasPopupUrl(int tab_id) const { | 262 bool ExtensionAction::HasPopupUrl(int tab_id) const { |
276 return HasValue(popup_url_, tab_id); | 263 return HasValue(popup_url_, tab_id); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
309 const extensions::ActionInfo& manifest_data) { | 296 const extensions::ActionInfo& manifest_data) { |
310 // If the manifest doesn't specify a title, set it to |extension|'s name. | 297 // If the manifest doesn't specify a title, set it to |extension|'s name. |
311 const std::string& title = | 298 const std::string& title = |
312 !manifest_data.default_title.empty() ? manifest_data.default_title : | 299 !manifest_data.default_title.empty() ? manifest_data.default_title : |
313 extension.name(); | 300 extension.name(); |
314 SetTitle(kDefaultTabId, title); | 301 SetTitle(kDefaultTabId, title); |
315 SetPopupUrl(kDefaultTabId, manifest_data.default_popup_url); | 302 SetPopupUrl(kDefaultTabId, manifest_data.default_popup_url); |
316 set_id(manifest_data.id); | 303 set_id(manifest_data.id); |
317 | 304 |
318 // Initialize the specified icon set. | 305 // Initialize the specified icon set. |
319 if (!manifest_data.default_icon.empty()) | 306 if (!manifest_data.default_icon.empty()) { |
320 default_icon_.reset(new ExtensionIconSet(manifest_data.default_icon)); | 307 default_icon_.reset(new ExtensionIconSet(manifest_data.default_icon)); |
321 | 308 } else { |
322 const ExtensionIconSet& extension_icons = | 309 // Fall back to the product icons if no action icon exists. |
323 extensions::IconsInfo::GetIcons(&extension); | 310 const ExtensionIconSet& product_icons = |
324 // Look for any other icons. | 311 extensions::IconsInfo::GetIcons(&extension); |
325 std::string largest_icon = extension_icons.Get( | 312 if (!product_icons.empty()) |
326 extension_misc::EXTENSION_ICON_GIGANTOR, ExtensionIconSet::MATCH_SMALLER); | 313 default_icon_.reset(new ExtensionIconSet(product_icons)); |
327 | |
328 if (!largest_icon.empty()) { | |
329 // We found an icon to use, so create an icon set if one doesn't exist. | |
330 if (!default_icon_) | |
331 default_icon_.reset(new ExtensionIconSet()); | |
332 int largest_icon_size = extension_icons.GetIconSizeFromPath(largest_icon); | |
333 // Replace any missing extension action icons with the largest icon | |
334 // retrieved from |extension|'s manifest so long as the largest icon is | |
335 // larger than the current key. | |
336 for (int i = extension_misc::kNumExtensionActionIconSizes - 1; i >= 0; | |
337 --i) { | |
338 int size = extension_misc::kExtensionActionIconSizes[i].size; | |
339 if (default_icon_->Get(size, ExtensionIconSet::MATCH_BIGGER).empty() && | |
340 largest_icon_size > size) { | |
341 default_icon_->Add(size, largest_icon); | |
342 break; | |
343 } | |
344 } | |
345 } | 314 } |
346 } | 315 } |
347 | 316 |
348 // Determines which icon would be returned by |GetIcon|, and returns its width. | 317 // Determines which icon would be returned by |GetIcon|, and returns its width. |
349 int ExtensionAction::GetIconWidth(int tab_id) const { | 318 int ExtensionAction::GetIconWidth(int tab_id) const { |
350 // If icon has been set, return its width. | 319 // If icon has been set, return its width. |
351 gfx::Image icon = GetValue(&icon_, tab_id); | 320 gfx::Image icon = GetValue(&icon_, tab_id); |
352 if (!icon.IsEmpty()) | 321 if (!icon.IsEmpty()) |
353 return icon.Width(); | 322 return icon.Width(); |
354 // If there is a default icon, the icon width will be set depending on our | 323 // If there is a default icon, the icon width will be set depending on our |
355 // action type. | 324 // action type. |
356 if (default_icon_) | 325 if (default_icon_) |
357 return GetIconSizeForType(action_type()); | 326 return ActionIconSize(); |
358 | 327 |
359 // If no icon has been set and there is no default icon, we need favicon | 328 // If no icon has been set and there is no default icon, we need favicon |
360 // width. | 329 // width. |
361 return ui::ResourceBundle::GetSharedInstance().GetImageNamed( | 330 return ui::ResourceBundle::GetSharedInstance().GetImageNamed( |
362 IDR_EXTENSIONS_FAVICON).Width(); | 331 IDR_EXTENSIONS_FAVICON).Width(); |
363 } | 332 } |
OLD | NEW |