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 3 // found in the LICENSE file. 4 5 #ifndef EXTENSIONS_BROWSER_EXTENSION_ACTION_H_ 6 #define EXTENSIONS_BROWSER_EXTENSION_ACTION_H_ 7 8 #include <map> 9 #include <memory> 10 #include <string> 11 #include <vector> 12 13 #include "base/macros.h" 14 #include "base/stl_util.h" 15 #include "extensions/common/api/extension_action/action_info.h" 16 #include "extensions/common/constants.h" 17 #include "third_party/skia/include/core/SkColor.h" 18 #include "ui/gfx/image/image.h" 19 20 class GURL; 21 22 namespace gfx { 23 class Image; 24 class ImageSkia; 25 } // namespace gfx 26 27 namespace extensions { 28 class Extension; 29 class IconImage; 30 31 // ExtensionAction encapsulates the state of a browser action or page action. 32 // Instances can have both global and per-tab state. If a property does not have 33 // a per-tab value, the global value is used instead. 34 class ExtensionAction { 35 public: 36 // The action that the UI should take after the ExtensionAction is clicked. 37 enum ShowAction { 38 ACTION_NONE, 39 ACTION_SHOW_POPUP, 40 // We don't need a SHOW_CONTEXT_MENU because that's handled separately in 41 // the UI. 42 }; 43 44 enum class IconParseResult { 45 kSuccess, 46 kDecodeFailure, 47 kUnpickleFailure, 48 }; 49 50 static extension_misc::ExtensionIcons ActionIconSize(); 51 52 // Returns the default icon to use when no other is available (the puzzle 53 // piece). 54 static gfx::Image FallbackIcon(); 55 56 // Use this ID to indicate the default state for properties that take a tab_id 57 // parameter. 58 static const int kDefaultTabId; 59 60 ExtensionAction(const Extension& extension, const ActionInfo& manifest_data); 61 ~ExtensionAction(); 62 63 // extension id extension_id()64 const std::string& extension_id() const { return extension_id_; } 65 66 // What kind of action is this? action_type()67 ActionInfo::Type action_type() const { return action_type_; } 68 default_state()69 ActionInfo::DefaultState default_state() const { return default_state_; } 70 71 // Set the url which the popup will load when the user clicks this action's 72 // icon. Setting an empty URL will disable the popup for a given tab. 73 void SetPopupUrl(int tab_id, const GURL& url); 74 75 // Use HasPopup() to see if a popup should be displayed. 76 bool HasPopup(int tab_id) const; 77 78 // Get the URL to display in a popup. 79 GURL GetPopupUrl(int tab_id) const; 80 81 // Set this action's title on a specific tab. SetTitle(int tab_id,const std::string & title)82 void SetTitle(int tab_id, const std::string& title) { 83 SetValue(&title_, tab_id, title); 84 } 85 86 // If tab |tab_id| has a set title, return it. Otherwise, return 87 // the default title. GetTitle(int tab_id)88 std::string GetTitle(int tab_id) const { return GetValue(&title_, tab_id); } 89 90 // Icons are a bit different because the default value can be set to either a 91 // bitmap or a path. However, conceptually, there is only one default icon. 92 // Setting the default icon using a path clears the bitmap and vice-versa. 93 // To retrieve the icon for the extension action, use 94 // ExtensionActionIconFactory. 95 96 // Set this action's icon bitmap on a specific tab. 97 void SetIcon(int tab_id, const gfx::Image& image); 98 99 // Tries to parse |*icon| from a dictionary {"19": imageData19, "38": 100 // imageData38}, and returns the result of the parsing attempt. 101 static IconParseResult ParseIconFromCanvasDictionary( 102 const base::DictionaryValue& dict, 103 gfx::ImageSkia* icon); 104 105 // Gets the icon that has been set using |SetIcon| for the tab. 106 gfx::Image GetExplicitlySetIcon(int tab_id) const; 107 108 // Sets the icon for a tab, in a way that can't be read by the extension's 109 // javascript. Multiple icons can be set at the same time; some icon with the 110 // highest priority will be used. 111 void DeclarativeSetIcon(int tab_id, int priority, const gfx::Image& icon); 112 void UndoDeclarativeSetIcon(int tab_id, int priority, const gfx::Image& icon); 113 default_icon()114 const ExtensionIconSet* default_icon() const { return default_icon_.get(); } 115 116 // Set this action's badge text on a specific tab. SetBadgeText(int tab_id,const std::string & text)117 void SetBadgeText(int tab_id, const std::string& text) { 118 SetValue(&badge_text_, tab_id, text); 119 } 120 121 // Clear this action's badge text on a specific tab. ClearBadgeText(int tab_id)122 void ClearBadgeText(int tab_id) { badge_text_.erase(tab_id); } 123 124 // Get the badge text that has been set using SetBadgeText for a tab, or the 125 // default if no badge text was set. GetExplicitlySetBadgeText(int tab_id)126 std::string GetExplicitlySetBadgeText(int tab_id) const { 127 return GetValue(&badge_text_, tab_id); 128 } 129 130 // Set this action's badge text color on a specific tab. SetBadgeTextColor(int tab_id,SkColor text_color)131 void SetBadgeTextColor(int tab_id, SkColor text_color) { 132 SetValue(&badge_text_color_, tab_id, text_color); 133 } 134 // Get the text color for a tab, or the default color if no text color 135 // was set. GetBadgeTextColor(int tab_id)136 SkColor GetBadgeTextColor(int tab_id) const { 137 return GetValue(&badge_text_color_, tab_id); 138 } 139 140 // Set this action's badge background color on a specific tab. SetBadgeBackgroundColor(int tab_id,SkColor color)141 void SetBadgeBackgroundColor(int tab_id, SkColor color) { 142 SetValue(&badge_background_color_, tab_id, color); 143 } 144 // Get the badge background color for a tab, or the default if no color 145 // was set. GetBadgeBackgroundColor(int tab_id)146 SkColor GetBadgeBackgroundColor(int tab_id) const { 147 return GetValue(&badge_background_color_, tab_id); 148 } 149 150 // Set this ExtensionAction's DNR matched action count on a specific tab. SetDNRActionCount(int tab_id,int action_count)151 void SetDNRActionCount(int tab_id, int action_count) { 152 SetValue(&dnr_action_count_, tab_id, action_count); 153 } 154 // Get this ExtensionAction's DNR matched action count on a specific tab. 155 // Returns -1 if no entry is found. GetDNRActionCount(int tab_id)156 int GetDNRActionCount(int tab_id) const { 157 return GetValue(&dnr_action_count_, tab_id); 158 } 159 // Clear this ExtensionAction's DNR matched action count for all tabs. ClearDNRActionCountForAllTabs()160 void ClearDNRActionCountForAllTabs() { dnr_action_count_.clear(); } 161 162 // Get the badge text displayed for a tab, calculated based on both 163 // |badge_text_| and |dnr_action_count_|. Returns in order of priority: 164 // - GetExplicitlySetBadgeText(tab_id) if it exists for the |tab_id| 165 // - GetDNRActionCount(tab_id) if there is at least one action for this tab 166 // - The default badge text, if set, otherwise: an empty string. 167 std::string GetDisplayBadgeText(int tab_id) const; 168 169 // Returns whether this extension action is using the DNR action count as its 170 // badge text. 171 bool UseDNRActionCountAsBadgeText(int tab_id) const; 172 173 // Set this action's badge visibility on a specific tab. Returns true if 174 // the visibility has changed. 175 bool SetIsVisible(int tab_id, bool value); 176 // The declarative appearance overrides a default appearance but is overridden 177 // by an appearance set directly on the tab. 178 void DeclarativeShow(int tab_id); 179 void UndoDeclarativeShow(int tab_id); 180 const gfx::Image GetDeclarativeIcon(int tab_id) const; 181 182 // Get the badge visibility for a tab, or the default badge visibility 183 // if none was set. 184 // Gets the visibility of |tab_id|. Returns the first of: a specific 185 // visibility set on the tab; a declarative visibility set on the tab; the 186 // default visibility set for all tabs; or |false|. Don't return this 187 // result to an extension's background page because the declarative state can 188 // leak information about hosts the extension doesn't have permission to 189 // access. GetIsVisible(int tab_id)190 bool GetIsVisible(int tab_id) const { 191 if (const bool* tab_is_visible = FindOrNull(&is_visible_, tab_id)) 192 return *tab_is_visible; 193 194 if (base::Contains(declarative_show_count_, tab_id)) 195 return true; 196 197 if (const bool* default_is_visible = 198 FindOrNull(&is_visible_, kDefaultTabId)) 199 return *default_is_visible; 200 201 return false; 202 } 203 204 // Remove all tab-specific state. 205 void ClearAllValuesForTab(int tab_id); 206 207 // Sets the default IconImage for this action. 208 void SetDefaultIconImage(std::unique_ptr<IconImage> icon_image); 209 210 // Returns the image to use as the default icon for the action. Can only be 211 // called after SetDefaultIconImage(). 212 gfx::Image GetDefaultIconImage() const; 213 214 // Returns the placeholder image for the extension. 215 gfx::Image GetPlaceholderIconImage() const; 216 217 // Determine whether or not the ExtensionAction has a value set for the given 218 // |tab_id| for each property. 219 bool HasPopupUrl(int tab_id) const; 220 bool HasTitle(int tab_id) const; 221 bool HasBadgeText(int tab_id) const; 222 bool HasBadgeBackgroundColor(int tab_id) const; 223 bool HasBadgeTextColor(int tab_id) const; 224 bool HasIsVisible(int tab_id) const; 225 bool HasIcon(int tab_id) const; 226 bool HasDNRActionCount(int tab_id) const; 227 default_icon_image()228 IconImage* default_icon_image() { return default_icon_image_.get(); } 229 230 void SetDefaultIconForTest(std::unique_ptr<ExtensionIconSet> default_icon); 231 232 private: 233 // Populates the action from the |extension| and |manifest_data|, filling in 234 // any missing values (like title or icons) as possible. 235 void Populate(const Extension& extension, const ActionInfo& manifest_data); 236 237 // Returns width of the current icon for tab_id. 238 // TODO(tbarzic): The icon selection is done in ExtensionActionIconFactory. 239 // We should probably move this there too. 240 int GetIconWidth(int tab_id) const; 241 242 template <class T> 243 struct ValueTraits { CreateEmptyValueTraits244 static T CreateEmpty() { return T(); } 245 }; 246 247 template <class T> SetValue(std::map<int,T> * map,int tab_id,const T & val)248 void SetValue(std::map<int, T>* map, int tab_id, const T& val) { 249 (*map)[tab_id] = val; 250 } 251 252 template <class Map> FindOrNull(const Map * map,const typename Map::key_type & key)253 static const typename Map::mapped_type* FindOrNull( 254 const Map* map, 255 const typename Map::key_type& key) { 256 typename Map::const_iterator iter = map->find(key); 257 if (iter == map->end()) 258 return NULL; 259 return &iter->second; 260 } 261 262 template <class T> GetValue(const std::map<int,T> * map,int tab_id)263 T GetValue(const std::map<int, T>* map, int tab_id) const { 264 if (const T* tab_value = FindOrNull(map, tab_id)) { 265 return *tab_value; 266 } else if (const T* default_value = FindOrNull(map, kDefaultTabId)) { 267 return *default_value; 268 } else { 269 return ValueTraits<T>::CreateEmpty(); 270 } 271 } 272 273 // The id for the extension this action belongs to (as defined in the 274 // extension manifest). 275 const std::string extension_id_; 276 277 // The name of the extension. 278 const std::string extension_name_; 279 280 const ActionInfo::Type action_type_; 281 // The default state of the action. 282 const ActionInfo::DefaultState default_state_; 283 284 // Each of these data items can have both a global state (stored with the key 285 // kDefaultTabId), or tab-specific state (stored with the tab_id as the key). 286 std::map<int, GURL> popup_url_; 287 std::map<int, std::string> title_; 288 std::map<int, gfx::Image> icon_; 289 std::map<int, std::string> badge_text_; 290 std::map<int, SkColor> badge_background_color_; 291 std::map<int, SkColor> badge_text_color_; 292 std::map<int, bool> is_visible_; 293 294 // Declarative state exists for two reasons: First, we need to hide it from 295 // the extension's background/event page to avoid leaking data from hosts the 296 // extension doesn't have permission to access. Second, the action's state 297 // gets both reset and given its declarative values in response to a 298 // WebContentsObserver::DidNavigateMainFrame event, and there's no way to set 299 // those up to be called in the right order. 300 301 // Maps tab_id to the number of active (applied-but-not-reverted) 302 // declarativeContent.ShowAction actions. 303 std::map<int, int> declarative_show_count_; 304 305 // declarative_icon_[tab_id][declarative_rule_priority] is a vector of icon 306 // images that are currently in effect 307 std::map<int, std::map<int, std::vector<gfx::Image>>> declarative_icon_; 308 309 // Maps tab_id to the number of actions taken based on declarative net request 310 // rule matches on incoming requests. Overrides the default |badge_text_| for 311 // this extension if it has opted into setting the action count as badge text. 312 std::map<int, int> dnr_action_count_; 313 314 // ExtensionIconSet containing paths to bitmaps from which default icon's 315 // image representations will be selected. 316 std::unique_ptr<ExtensionIconSet> default_icon_; 317 318 // The default icon image, if |default_icon_| exists. Set via 319 // SetDefaultIconImage(). Since IconImages depend upon BrowserContexts, we 320 // don't have the ExtensionAction load it directly to keep this class's 321 // knowledge limited. 322 std::unique_ptr<IconImage> default_icon_image_; 323 324 // The lazily-initialized image for a placeholder icon, in the event that the 325 // extension doesn't have its own icon. (Mutable to allow lazy init in 326 // GetDefaultIconImage().) 327 mutable gfx::Image placeholder_icon_image_; 328 329 // The id for the ExtensionAction, for example: "RssPageAction". This is 330 // needed for compat with an older version of the page actions API. 331 std::string id_; 332 333 DISALLOW_COPY_AND_ASSIGN(ExtensionAction); 334 }; 335 336 template <> 337 struct ExtensionAction::ValueTraits<int> { 338 static int CreateEmpty() { return -1; } 339 }; 340 341 } // namespace extensions 342 343 #endif // EXTENSIONS_BROWSER_EXTENSION_ACTION_H_ 344