Index: chrome/browser/extensions/extension_action.h |
diff --git a/chrome/browser/extensions/extension_action.h b/chrome/browser/extensions/extension_action.h |
index dacd961ee03bb531df0289fc9037730a03071ccf..943a3eb4ab96f5396c56df700af56b781c3d619a 100644 |
--- a/chrome/browser/extensions/extension_action.h |
+++ b/chrome/browser/extensions/extension_action.h |
@@ -220,15 +220,20 @@ class ExtensionAction { |
// care of any appropriate transition animations. Returns true if |
// the appearance has changed. |
bool SetAppearance(int tab_id, Appearance value); |
+ // The declarative appearance overrides a default appearance but is overridden |
+ // by an appearance set directly on the tab. |
+ void DeclarativeShow(int tab_id); |
+ void UndoDeclarativeShow(int tab_id); |
+ |
// Get the badge visibility for a tab, or the default badge visibility |
// if none was set. |
bool GetIsVisible(int tab_id) const { |
- return GetValue(&appearance_, tab_id) != INVISIBLE; |
+ return GetAppearance(tab_id) != INVISIBLE; |
} |
// True if the tab's action wants the user's attention. |
bool WantsAttention(int tab_id) const { |
- return GetValue(&appearance_, tab_id) == WANTS_ATTENTION; |
+ return GetAppearance(tab_id) == WANTS_ATTENTION; |
} |
// Remove all tab-specific state. |
@@ -272,17 +277,47 @@ class ExtensionAction { |
(*map)[tab_id] = val; |
} |
+ template<class Map> |
+ static const typename Map::mapped_type* FindOrNull( |
+ const Map* map, |
+ const typename Map::key_type& key) { |
+ typename Map::const_iterator iter = map->find(key); |
+ if (iter == map->end()) |
+ return NULL; |
+ return &iter->second; |
+ } |
+ |
template<class T> |
T GetValue(const std::map<int, T>* map, int tab_id) const { |
- typename std::map<int, T>::const_iterator iter = map->find(tab_id); |
- if (iter != map->end()) { |
- return iter->second; |
+ if (const T* tab_value = FindOrNull(map, tab_id)) { |
+ return *tab_value; |
+ } else if (const T* default_value = FindOrNull(map, kDefaultTabId)) { |
+ return *default_value; |
} else { |
- iter = map->find(kDefaultTabId); |
- return iter != map->end() ? iter->second : ValueTraits<T>::CreateEmpty(); |
+ return ValueTraits<T>::CreateEmpty(); |
} |
} |
+ // Gets the appearance of |tab_id|. Returns the first of: a specific |
+ // appearance set on the tab; a declarative appearance set on the tab; the |
+ // default appearance set for all tabs; or INVISIBLE. Don't return this |
+ // result to an extension's background page because the declarative state can |
+ // leak information about hosts the extension doesn't have permission to |
Matt Perry
2013/01/24 01:55:17
This means we can't expose whether a page action i
Jeffrey Yasskin
2013/01/24 03:10:22
It means that we have to expose the state the exte
|
+ // access. |
+ Appearance GetAppearance(int tab_id) const { |
+ if (const Appearance* tab_appearance = FindOrNull(&appearance_, tab_id)) |
+ return *tab_appearance; |
+ |
+ if (ContainsKey(declarative_show_count_, tab_id)) |
+ return ACTIVE; |
+ |
+ if (const Appearance* default_appearance = |
+ FindOrNull(&appearance_, kDefaultTabId)) |
+ return *default_appearance; |
+ |
+ return INVISIBLE; |
+ } |
+ |
// The id for the extension this action belongs to (as defined in the |
// extension manifest). |
const std::string extension_id_; |
@@ -299,6 +334,17 @@ class ExtensionAction { |
std::map<int, SkColor> badge_text_color_; |
std::map<int, Appearance> appearance_; |
+ // Declarative state exists for two reasons: First, we need to hide it from |
+ // the extension's background/event page to avoid leaking data from hosts the |
+ // extension doesn't have permission to access. Second, the action's state |
+ // gets both reset and given its declarative values in response to a |
+ // WebContentsObserver::DidNavigateMainFrame event, and there's no way to set |
+ // those up to be called in the right order. |
+ |
+ // Maps tab_id to the number of active (applied-but-not-reverted) |
+ // declarativeContent.ShowPageAction actions. |
+ std::map<int, int> declarative_show_count_; |
+ |
// IconAnimations are destroyed by a delayed task on the UI message loop so |
// that even if the Extension and ExtensionAction are destroyed on a non-UI |
// thread, the animation will still only be touched from the UI thread. This |