Chromium Code Reviews| 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>(ExtensionAction::ActionIconSize()) / icon_size; | |
| 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. |
|
Evan Stade
2015/12/02 23:25:32
this is a behavioral change (and for the better, I
Devlin
2015/12/03 00:00:37
+1
| |
| 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 |