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 CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_H_ 6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_H_ 7 8 #include <map> 9 #include <string> 10 #include <vector> 11 12 #include "base/basictypes.h" 13 #include "base/memory/linked_ptr.h" 14 #include "base/memory/scoped_ptr.h" 15 #include "base/memory/scoped_vector.h" 16 #include "base/memory/weak_ptr.h" 17 #include "base/observer_list.h" 18 #include "chrome/common/extensions/api/extension_action/action_info.h" 19 #include "extensions/common/extension_icon_set.h" 20 #include "third_party/skia/include/core/SkColor.h" 21 // TODO(robertphillips): change this to "class SkBaseDevice;" 22 #include "third_party/skia/include/core/SkDevice.h" 23 #include "ui/gfx/animation/linear_animation.h" 24 25 class GURL; 26 class SkBitmap; 27 28 namespace gfx { 29 class Canvas; 30 class Image; 31 class ImageSkia; 32 class Rect; 33 class Size; 34 } 35 36 // ExtensionAction encapsulates the state of a browser action or page action. 37 // Instances can have both global and per-tab state. If a property does not have 38 // a per-tab value, the global value is used instead. 39 class ExtensionAction { 40 public: 41 // The action that the UI should take after the ExtensionAction is clicked. 42 enum ShowAction { 43 ACTION_NONE, 44 ACTION_SHOW_POPUP, 45 // We don't need a SHOW_CONTEXT_MENU because that's handled separately in 46 // the UI. 47 }; 48 49 // Use this ID to indicate the default state for properties that take a tab_id 50 // parameter. 51 static const int kDefaultTabId; 52 53 // Max size (both dimensions) for page actions. 54 static const int kPageActionIconMaxSize; 55 56 ExtensionAction(const std::string& extension_id, 57 extensions::ActionInfo::Type action_type, 58 const extensions::ActionInfo& manifest_data); 59 ~ExtensionAction(); 60 61 // Gets a copy of this, ownership passed to caller. 62 // It doesn't make sense to copy of an ExtensionAction except in tests. 63 scoped_ptr<ExtensionAction> CopyForTest() const; 64 65 // Given the extension action type, returns the size the extension action icon 66 // should have. The icon should be square, so only one dimension is 67 // returned. 68 static int GetIconSizeForType(extensions::ActionInfo::Type type); 69 70 // extension id extension_id()71 const std::string& extension_id() const { return extension_id_; } 72 73 // What kind of action is this? action_type()74 extensions::ActionInfo::Type action_type() const { 75 return action_type_; 76 } 77 78 // action id -- only used with legacy page actions API id()79 std::string id() const { return id_; } set_id(const std::string & id)80 void set_id(const std::string& id) { id_ = id; } 81 82 // Set the url which the popup will load when the user clicks this action's 83 // icon. Setting an empty URL will disable the popup for a given tab. 84 void SetPopupUrl(int tab_id, const GURL& url); 85 86 // Use HasPopup() to see if a popup should be displayed. 87 bool HasPopup(int tab_id) const; 88 89 // Get the URL to display in a popup. 90 GURL GetPopupUrl(int tab_id) const; 91 92 // Set this action's title on a specific tab. SetTitle(int tab_id,const std::string & title)93 void SetTitle(int tab_id, const std::string& title) { 94 SetValue(&title_, tab_id, title); 95 } 96 97 // If tab |tab_id| has a set title, return it. Otherwise, return 98 // the default title. GetTitle(int tab_id)99 std::string GetTitle(int tab_id) const { return GetValue(&title_, tab_id); } 100 101 // Icons are a bit different because the default value can be set to either a 102 // bitmap or a path. However, conceptually, there is only one default icon. 103 // Setting the default icon using a path clears the bitmap and vice-versa. 104 // To retrieve the icon for the extension action, use 105 // ExtensionActionIconFactory. 106 107 // Set this action's icon bitmap on a specific tab. 108 void SetIcon(int tab_id, const gfx::Image& image); 109 110 // Tries to parse |*icon| from a dictionary {"19": imageData19, "38": 111 // imageData38}, returning false if a value is corrupt. 112 static bool ParseIconFromCanvasDictionary(const base::DictionaryValue& dict, 113 gfx::ImageSkia* icon); 114 115 // Gets the icon that has been set using |SetIcon| for the tab. 116 gfx::ImageSkia GetExplicitlySetIcon(int tab_id) const; 117 118 // Sets the icon for a tab, in a way that can't be read by the extension's 119 // javascript. Multiple icons can be set at the same time; some icon with the 120 // highest priority will be used. 121 void DeclarativeSetIcon(int tab_id, int priority, const gfx::Image& icon); 122 void UndoDeclarativeSetIcon(int tab_id, int priority, const gfx::Image& icon); 123 124 // Non-tab-specific icon path. This is used to support the default_icon key of 125 // page and browser actions. set_default_icon(scoped_ptr<ExtensionIconSet> icon_set)126 void set_default_icon(scoped_ptr<ExtensionIconSet> icon_set) { 127 default_icon_ = icon_set.Pass(); 128 } 129 default_icon()130 const ExtensionIconSet* default_icon() const { 131 return default_icon_.get(); 132 } 133 134 // Set this action's badge text on a specific tab. SetBadgeText(int tab_id,const std::string & text)135 void SetBadgeText(int tab_id, const std::string& text) { 136 SetValue(&badge_text_, tab_id, text); 137 } 138 // Get the badge text for a tab, or the default if no badge text was set. GetBadgeText(int tab_id)139 std::string GetBadgeText(int tab_id) const { 140 return GetValue(&badge_text_, tab_id); 141 } 142 143 // Set this action's badge text color on a specific tab. SetBadgeTextColor(int tab_id,SkColor text_color)144 void SetBadgeTextColor(int tab_id, SkColor text_color) { 145 SetValue(&badge_text_color_, tab_id, text_color); 146 } 147 // Get the text color for a tab, or the default color if no text color 148 // was set. GetBadgeTextColor(int tab_id)149 SkColor GetBadgeTextColor(int tab_id) const { 150 return GetValue(&badge_text_color_, tab_id); 151 } 152 153 // Set this action's badge background color on a specific tab. SetBadgeBackgroundColor(int tab_id,SkColor color)154 void SetBadgeBackgroundColor(int tab_id, SkColor color) { 155 SetValue(&badge_background_color_, tab_id, color); 156 } 157 // Get the badge background color for a tab, or the default if no color 158 // was set. GetBadgeBackgroundColor(int tab_id)159 SkColor GetBadgeBackgroundColor(int tab_id) const { 160 return GetValue(&badge_background_color_, tab_id); 161 } 162 163 // Set this action's badge visibility on a specific tab. Returns true if 164 // the visibility has changed. 165 bool SetIsVisible(int tab_id, bool value); 166 // The declarative appearance overrides a default appearance but is overridden 167 // by an appearance set directly on the tab. 168 void DeclarativeShow(int tab_id); 169 void UndoDeclarativeShow(int tab_id); 170 const gfx::ImageSkia GetDeclarativeIcon(int tab_id) const; 171 172 // Get the badge visibility for a tab, or the default badge visibility 173 // if none was set. 174 // Gets the visibility of |tab_id|. Returns the first of: a specific 175 // visibility set on the tab; a declarative visibility set on the tab; the 176 // default visibility set for all tabs; or |false|. Don't return this 177 // result to an extension's background page because the declarative state can 178 // leak information about hosts the extension doesn't have permission to 179 // access. GetIsVisible(int tab_id)180 bool GetIsVisible(int tab_id) const { 181 if (const bool* tab_is_visible = FindOrNull(&is_visible_, tab_id)) 182 return *tab_is_visible; 183 184 if (ContainsKey(declarative_show_count_, tab_id)) 185 return true; 186 187 if (const bool* default_is_visible = 188 FindOrNull(&is_visible_, kDefaultTabId)) 189 return *default_is_visible; 190 191 return false; 192 } 193 194 // Remove all tab-specific state. 195 void ClearAllValuesForTab(int tab_id); 196 197 // If the specified tab has a badge, paint it into the provided bounds. 198 void PaintBadge(gfx::Canvas* canvas, const gfx::Rect& bounds, int tab_id); 199 200 // Returns icon image with badge for specified tab. 201 gfx::ImageSkia GetIconWithBadge(const gfx::ImageSkia& icon, 202 int tab_id, 203 const gfx::Size& spacing) const; 204 205 // Determine whether or not the ExtensionAction has a value set for the given 206 // |tab_id| for each property. 207 bool HasPopupUrl(int tab_id) const; 208 bool HasTitle(int tab_id) const; 209 bool HasBadgeText(int tab_id) const; 210 bool HasBadgeBackgroundColor(int tab_id) const; 211 bool HasBadgeTextColor(int tab_id) const; 212 bool HasIsVisible(int tab_id) const; 213 bool HasIcon(int tab_id) const; 214 215 private: 216 // Returns width of the current icon for tab_id. 217 // TODO(tbarzic): The icon selection is done in ExtensionActionIconFactory. 218 // We should probably move this there too. 219 int GetIconWidth(int tab_id) const; 220 221 template <class T> 222 struct ValueTraits { CreateEmptyValueTraits223 static T CreateEmpty() { 224 return T(); 225 } 226 }; 227 228 template<class T> SetValue(std::map<int,T> * map,int tab_id,const T & val)229 void SetValue(std::map<int, T>* map, int tab_id, const T& val) { 230 (*map)[tab_id] = val; 231 } 232 233 template<class Map> FindOrNull(const Map * map,const typename Map::key_type & key)234 static const typename Map::mapped_type* FindOrNull( 235 const Map* map, 236 const typename Map::key_type& key) { 237 typename Map::const_iterator iter = map->find(key); 238 if (iter == map->end()) 239 return NULL; 240 return &iter->second; 241 } 242 243 template<class T> GetValue(const std::map<int,T> * map,int tab_id)244 T GetValue(const std::map<int, T>* map, int tab_id) const { 245 if (const T* tab_value = FindOrNull(map, tab_id)) { 246 return *tab_value; 247 } else if (const T* default_value = FindOrNull(map, kDefaultTabId)) { 248 return *default_value; 249 } else { 250 return ValueTraits<T>::CreateEmpty(); 251 } 252 } 253 254 // The id for the extension this action belongs to (as defined in the 255 // extension manifest). 256 const std::string extension_id_; 257 258 const extensions::ActionInfo::Type action_type_; 259 260 // Each of these data items can have both a global state (stored with the key 261 // kDefaultTabId), or tab-specific state (stored with the tab_id as the key). 262 std::map<int, GURL> popup_url_; 263 std::map<int, std::string> title_; 264 std::map<int, gfx::ImageSkia> icon_; 265 std::map<int, std::string> badge_text_; 266 std::map<int, SkColor> badge_background_color_; 267 std::map<int, SkColor> badge_text_color_; 268 std::map<int, bool> is_visible_; 269 270 // Declarative state exists for two reasons: First, we need to hide it from 271 // the extension's background/event page to avoid leaking data from hosts the 272 // extension doesn't have permission to access. Second, the action's state 273 // gets both reset and given its declarative values in response to a 274 // WebContentsObserver::DidNavigateMainFrame event, and there's no way to set 275 // those up to be called in the right order. 276 277 // Maps tab_id to the number of active (applied-but-not-reverted) 278 // declarativeContent.ShowPageAction actions. 279 std::map<int, int> declarative_show_count_; 280 281 // declarative_icon_[tab_id][declarative_rule_priority] is a vector of icon 282 // images that are currently in effect 283 std::map<int, std::map<int, std::vector<gfx::Image> > > declarative_icon_; 284 285 // ExtensionIconSet containing paths to bitmaps from which default icon's 286 // image representations will be selected. 287 scoped_ptr<const ExtensionIconSet> default_icon_; 288 289 // The id for the ExtensionAction, for example: "RssPageAction". This is 290 // needed for compat with an older version of the page actions API. 291 std::string id_; 292 293 DISALLOW_COPY_AND_ASSIGN(ExtensionAction); 294 }; 295 296 template<> 297 struct ExtensionAction::ValueTraits<int> { 298 static int CreateEmpty() { 299 return -1; 300 } 301 }; 302 303 #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_H_ 304