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.
5 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_H_
6 #define CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_H_
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 "chrome/common/extensions/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"
36 // ExtensionAction encapsulates the state of a browser action, page action, or
38 // Instances can have both global and per-tab state. If a property does not have
39 // a per-tab value, the global value is used instead.
40 class ExtensionAction
{
42 // Use this ID to indicate the default state for properties that take a tab_id
44 static const int kDefaultTabId
;
47 // The action icon is hidden.
49 // The action is trying to get the user's attention but isn't yet
50 // running on the page. Currently only used for script badges.
52 // The action icon is visible with its normal appearance.
56 // A fade-in animation.
57 class IconAnimation
: public gfx::LinearAnimation
{
59 // Observes changes to icon animation state.
62 virtual void OnIconChanged() = 0;
65 virtual ~Observer() {}
68 // A holder for an IconAnimation with a scoped observer.
69 class ScopedObserver
{
71 ScopedObserver(const base::WeakPtr
<IconAnimation
>& icon_animation
,
75 // Gets the icon animation, or NULL if the reference has expired.
76 const IconAnimation
* icon_animation() const {
77 return icon_animation_
.get();
81 base::WeakPtr
<IconAnimation
> icon_animation_
;
84 DISALLOW_COPY_AND_ASSIGN(ScopedObserver
);
87 virtual ~IconAnimation();
89 // Returns the icon derived from the current animation state applied to
90 // |icon|. Ownership remains with this.
91 const SkBitmap
& Apply(const SkBitmap
& icon
) const;
93 void AddObserver(Observer
* observer
);
94 void RemoveObserver(Observer
* observer
);
97 // Construct using ExtensionAction::RunIconAnimation().
98 friend class ExtensionAction
;
101 base::WeakPtr
<IconAnimation
> AsWeakPtr();
103 // gfx::LinearAnimation implementation.
104 virtual void AnimateToState(double state
) OVERRIDE
;
106 // Device we use to paint icons to.
107 mutable scoped_ptr
<SkBaseDevice
> device_
;
109 ObserverList
<Observer
> observers_
;
111 base::WeakPtrFactory
<IconAnimation
> weak_ptr_factory_
;
113 DISALLOW_COPY_AND_ASSIGN(IconAnimation
);
116 ExtensionAction(const std::string
& extension_id
,
117 extensions::ActionInfo::Type action_type
,
118 const extensions::ActionInfo
& manifest_data
);
121 // Gets a copy of this, ownership passed to caller.
122 // It doesn't make sense to copy of an ExtensionAction except in tests.
123 scoped_ptr
<ExtensionAction
> CopyForTest() const;
125 // Given the extension action type, returns the size the extension action icon
126 // should have. The icon should be square, so only one dimension is
128 static int GetIconSizeForType(extensions::ActionInfo::Type type
);
131 const std::string
& extension_id() const { return extension_id_
; }
133 // What kind of action is this?
134 extensions::ActionInfo::Type
action_type() const {
138 // action id -- only used with legacy page actions API
139 std::string
id() const { return id_
; }
140 void set_id(const std::string
& id
) { id_
= id
; }
142 bool has_changed() const { return has_changed_
; }
143 void set_has_changed(bool value
) { has_changed_
= value
; }
145 // Set the url which the popup will load when the user clicks this action's
146 // icon. Setting an empty URL will disable the popup for a given tab.
147 void SetPopupUrl(int tab_id
, const GURL
& url
);
149 // Use HasPopup() to see if a popup should be displayed.
150 bool HasPopup(int tab_id
) const;
152 // Get the URL to display in a popup.
153 GURL
GetPopupUrl(int tab_id
) const;
155 // Set this action's title on a specific tab.
156 void SetTitle(int tab_id
, const std::string
& title
) {
157 SetValue(&title_
, tab_id
, title
);
160 // If tab |tab_id| has a set title, return it. Otherwise, return
161 // the default title.
162 std::string
GetTitle(int tab_id
) const { return GetValue(&title_
, tab_id
); }
164 // Icons are a bit different because the default value can be set to either a
165 // bitmap or a path. However, conceptually, there is only one default icon.
166 // Setting the default icon using a path clears the bitmap and vice-versa.
167 // To retrieve the icon for the extension action, use
168 // ExtensionActionIconFactory.
170 // Set this action's icon bitmap on a specific tab.
171 void SetIcon(int tab_id
, const gfx::Image
& image
);
173 // Applies the attention and animation image transformations registered for
174 // the tab on the provided icon.
175 gfx::Image
ApplyAttentionAndAnimation(const gfx::ImageSkia
& icon
,
178 // Gets the icon that has been set using |SetIcon| for the tab.
179 gfx::ImageSkia
GetExplicitlySetIcon(int tab_id
) const;
181 // Non-tab-specific icon path. This is used to support the default_icon key of
182 // page and browser actions.
183 void set_default_icon(scoped_ptr
<ExtensionIconSet
> icon_set
) {
184 default_icon_
= icon_set
.Pass();
187 const ExtensionIconSet
* default_icon() const {
188 return default_icon_
.get();
191 // Set this action's badge text on a specific tab.
192 void SetBadgeText(int tab_id
, const std::string
& text
) {
193 SetValue(&badge_text_
, tab_id
, text
);
195 // Get the badge text for a tab, or the default if no badge text was set.
196 std::string
GetBadgeText(int tab_id
) const {
197 return GetValue(&badge_text_
, tab_id
);
200 // Set this action's badge text color on a specific tab.
201 void SetBadgeTextColor(int tab_id
, SkColor text_color
) {
202 SetValue(&badge_text_color_
, tab_id
, text_color
);
204 // Get the text color for a tab, or the default color if no text color
206 SkColor
GetBadgeTextColor(int tab_id
) const {
207 return GetValue(&badge_text_color_
, tab_id
);
210 // Set this action's badge background color on a specific tab.
211 void SetBadgeBackgroundColor(int tab_id
, SkColor color
) {
212 SetValue(&badge_background_color_
, tab_id
, color
);
214 // Get the badge background color for a tab, or the default if no color
216 SkColor
GetBadgeBackgroundColor(int tab_id
) const {
217 return GetValue(&badge_background_color_
, tab_id
);
220 // Set this action's badge visibility on a specific tab. This takes
221 // care of any appropriate transition animations. Returns true if
222 // the appearance has changed.
223 bool SetAppearance(int tab_id
, Appearance value
);
224 // The declarative appearance overrides a default appearance but is overridden
225 // by an appearance set directly on the tab.
226 void DeclarativeShow(int tab_id
);
227 void UndoDeclarativeShow(int tab_id
);
229 // Get the badge visibility for a tab, or the default badge visibility
231 bool GetIsVisible(int tab_id
) const {
232 return GetAppearance(tab_id
) != INVISIBLE
;
235 // True if the tab's action wants the user's attention.
236 bool WantsAttention(int tab_id
) const {
237 return GetAppearance(tab_id
) == WANTS_ATTENTION
;
240 // Remove all tab-specific state.
241 void ClearAllValuesForTab(int tab_id
);
243 // If the specified tab has a badge, paint it into the provided bounds.
244 void PaintBadge(gfx::Canvas
* canvas
, const gfx::Rect
& bounds
, int tab_id
);
246 // Returns icon image with badge for specified tab.
247 gfx::ImageSkia
GetIconWithBadge(const gfx::ImageSkia
& icon
,
249 const gfx::Size
& spacing
) const;
251 // Gets a weak reference to the icon animation for a tab, if any. The
252 // reference will only have a value while the animation is running.
253 base::WeakPtr
<IconAnimation
> GetIconAnimation(int tab_id
) const;
256 // Runs an animation on a tab.
257 void RunIconAnimation(int tab_id
);
259 // If the icon animation is running on tab |tab_id|, applies it to
260 // |orig| and returns the result. Otherwise, just returns |orig|.
261 gfx::ImageSkia
ApplyIconAnimation(int tab_id
,
262 const gfx::ImageSkia
& orig
) const;
264 // Returns width of the current icon for tab_id.
265 // TODO(tbarzic): The icon selection is done in ExtensionActionIconFactory.
266 // We should probably move this there too.
267 int GetIconWidth(int tab_id
) const;
271 static T
CreateEmpty() {
277 void SetValue(std::map
<int, T
>* map
, int tab_id
, const T
& val
) {
278 (*map
)[tab_id
] = val
;
282 static const typename
Map::mapped_type
* FindOrNull(
284 const typename
Map::key_type
& key
) {
285 typename
Map::const_iterator iter
= map
->find(key
);
286 if (iter
== map
->end())
288 return &iter
->second
;
292 T
GetValue(const std::map
<int, T
>* map
, int tab_id
) const {
293 if (const T
* tab_value
= FindOrNull(map
, tab_id
)) {
295 } else if (const T
* default_value
= FindOrNull(map
, kDefaultTabId
)) {
296 return *default_value
;
298 return ValueTraits
<T
>::CreateEmpty();
302 // Gets the appearance of |tab_id|. Returns the first of: a specific
303 // appearance set on the tab; a declarative appearance set on the tab; the
304 // default appearance set for all tabs; or INVISIBLE. Don't return this
305 // result to an extension's background page because the declarative state can
306 // leak information about hosts the extension doesn't have permission to
308 Appearance
GetAppearance(int tab_id
) const {
309 if (const Appearance
* tab_appearance
= FindOrNull(&appearance_
, tab_id
))
310 return *tab_appearance
;
312 if (ContainsKey(declarative_show_count_
, tab_id
))
315 if (const Appearance
* default_appearance
=
316 FindOrNull(&appearance_
, kDefaultTabId
))
317 return *default_appearance
;
322 // The id for the extension this action belongs to (as defined in the
323 // extension manifest).
324 const std::string extension_id_
;
326 const extensions::ActionInfo::Type action_type_
;
328 // Each of these data items can have both a global state (stored with the key
329 // kDefaultTabId), or tab-specific state (stored with the tab_id as the key).
330 std::map
<int, GURL
> popup_url_
;
331 std::map
<int, std::string
> title_
;
332 std::map
<int, gfx::ImageSkia
> icon_
;
333 std::map
<int, std::string
> badge_text_
;
334 std::map
<int, SkColor
> badge_background_color_
;
335 std::map
<int, SkColor
> badge_text_color_
;
336 std::map
<int, Appearance
> appearance_
;
338 // Declarative state exists for two reasons: First, we need to hide it from
339 // the extension's background/event page to avoid leaking data from hosts the
340 // extension doesn't have permission to access. Second, the action's state
341 // gets both reset and given its declarative values in response to a
342 // WebContentsObserver::DidNavigateMainFrame event, and there's no way to set
343 // those up to be called in the right order.
345 // Maps tab_id to the number of active (applied-but-not-reverted)
346 // declarativeContent.ShowPageAction actions.
347 std::map
<int, int> declarative_show_count_
;
349 // IconAnimations are destroyed by a delayed task on the UI message loop so
350 // that even if the Extension and ExtensionAction are destroyed on a non-UI
351 // thread, the animation will still only be touched from the UI thread. This
352 // causes the WeakPtr in this map to become NULL. GetIconAnimation() removes
353 // NULLs to prevent the map from growing without bound.
354 mutable std::map
<int, base::WeakPtr
<IconAnimation
> > icon_animation_
;
356 // ExtensionIconSet containing paths to bitmaps from which default icon's
357 // image representations will be selected.
358 scoped_ptr
<const ExtensionIconSet
> default_icon_
;
360 // The id for the ExtensionAction, for example: "RssPageAction". This is
361 // needed for compat with an older version of the page actions API.
364 // True if the ExtensionAction's settings have changed from what was
365 // specified in the manifest.
368 DISALLOW_COPY_AND_ASSIGN(ExtensionAction
);
372 struct ExtensionAction::ValueTraits
<int> {
373 static int CreateEmpty() {
378 #endif // CHROME_BROWSER_EXTENSIONS_EXTENSION_ACTION_H_