Home | History | Annotate | Download | only in extensions
      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
     71   const std::string& extension_id() const { return extension_id_; }
     72 
     73   // What kind of action is this?
     74   extensions::ActionInfo::Type action_type() const {
     75     return action_type_;
     76   }
     77 
     78   // action id -- only used with legacy page actions API
     79   std::string id() const { return 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.
     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.
     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.
    126   void set_default_icon(scoped_ptr<ExtensionIconSet> icon_set) {
    127      default_icon_ = icon_set.Pass();
    128   }
    129 
    130   const ExtensionIconSet* default_icon() const {
    131     return default_icon_.get();
    132   }
    133 
    134   // Set this action's badge text on a specific tab.
    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.
    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.
    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.
    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.
    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.
    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.
    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 {
    223     static T CreateEmpty() {
    224       return T();
    225     }
    226   };
    227 
    228   template<class T>
    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>
    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>
    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