• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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