Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / extensions / extension_action.cc
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 #include "chrome/browser/extensions/extension_action.h"
6
7 #include <algorithm>
8
9 #include "base/bind.h"
10 #include "base/logging.h"
11 #include "base/message_loop/message_loop.h"
12 #include "chrome/common/badge_util.h"
13 #include "chrome/common/icon_with_badge_image_source.h"
14 #include "extensions/common/constants.h"
15 #include "grit/theme_resources.h"
16 #include "grit/ui_resources.h"
17 #include "third_party/skia/include/core/SkBitmap.h"
18 #include "third_party/skia/include/core/SkCanvas.h"
19 #include "third_party/skia/include/core/SkPaint.h"
20 #include "third_party/skia/include/effects/SkGradientShader.h"
21 #include "ui/base/resource/resource_bundle.h"
22 #include "ui/gfx/animation/animation_delegate.h"
23 #include "ui/gfx/canvas.h"
24 #include "ui/gfx/color_utils.h"
25 #include "ui/gfx/image/image.h"
26 #include "ui/gfx/image/image_skia.h"
27 #include "ui/gfx/image/image_skia_source.h"
28 #include "ui/gfx/rect.h"
29 #include "ui/gfx/size.h"
30 #include "ui/gfx/skbitmap_operations.h"
31 #include "url/gurl.h"
32
33 namespace {
34
35 class GetAttentionImageSource : public gfx::ImageSkiaSource {
36  public:
37   explicit GetAttentionImageSource(const gfx::ImageSkia& icon)
38       : icon_(icon) {}
39
40   // gfx::ImageSkiaSource overrides:
41   virtual gfx::ImageSkiaRep GetImageForScale(float scale) OVERRIDE {
42     gfx::ImageSkiaRep icon_rep = icon_.GetRepresentation(scale);
43     color_utils::HSL shift = {-1, 0, 0.5};
44     return gfx::ImageSkiaRep(
45         SkBitmapOperations::CreateHSLShiftedBitmap(icon_rep.sk_bitmap(), shift),
46         icon_rep.scale());
47   }
48
49  private:
50   const gfx::ImageSkia icon_;
51 };
52
53 template <class T>
54 bool HasValue(const std::map<int, T>& map, int tab_id) {
55   return map.find(tab_id) != map.end();
56 }
57
58 }  // namespace
59
60 const int ExtensionAction::kDefaultTabId = -1;
61 const int ExtensionAction::kPageActionIconMaxSize = 19;
62
63 ExtensionAction::ExtensionAction(const std::string& extension_id,
64                                  extensions::ActionInfo::Type action_type,
65                                  const extensions::ActionInfo& manifest_data)
66     : extension_id_(extension_id), action_type_(action_type) {
67   // Page/script actions are hidden/disabled by default, and browser actions are
68   // visible/enabled by default.
69   SetIsVisible(kDefaultTabId,
70                action_type == extensions::ActionInfo::TYPE_BROWSER);
71   SetTitle(kDefaultTabId, manifest_data.default_title);
72   SetPopupUrl(kDefaultTabId, manifest_data.default_popup_url);
73   if (!manifest_data.default_icon.empty()) {
74     set_default_icon(make_scoped_ptr(new ExtensionIconSet(
75         manifest_data.default_icon)));
76   }
77   set_id(manifest_data.id);
78 }
79
80 ExtensionAction::~ExtensionAction() {
81 }
82
83 scoped_ptr<ExtensionAction> ExtensionAction::CopyForTest() const {
84   scoped_ptr<ExtensionAction> copy(
85       new ExtensionAction(extension_id_, action_type_,
86                           extensions::ActionInfo()));
87   copy->popup_url_ = popup_url_;
88   copy->title_ = title_;
89   copy->icon_ = icon_;
90   copy->badge_text_ = badge_text_;
91   copy->badge_background_color_ = badge_background_color_;
92   copy->badge_text_color_ = badge_text_color_;
93   copy->is_visible_ = is_visible_;
94   copy->id_ = id_;
95
96   if (default_icon_)
97     copy->default_icon_.reset(new ExtensionIconSet(*default_icon_));
98
99   return copy.Pass();
100 }
101
102 // static
103 int ExtensionAction::GetIconSizeForType(
104     extensions::ActionInfo::Type type) {
105   switch (type) {
106     case extensions::ActionInfo::TYPE_BROWSER:
107     case extensions::ActionInfo::TYPE_PAGE:
108     case extensions::ActionInfo::TYPE_SYSTEM_INDICATOR:
109       // TODO(dewittj) Report the actual icon size of the system
110       // indicator.
111       return extension_misc::EXTENSION_ICON_ACTION;
112     default:
113       NOTREACHED();
114       return 0;
115   }
116 }
117
118 void ExtensionAction::SetPopupUrl(int tab_id, const GURL& url) {
119   // We store |url| even if it is empty, rather than removing a URL from the
120   // map.  If an extension has a default popup, and removes it for a tab via
121   // the API, we must remember that there is no popup for that specific tab.
122   // If we removed the tab's URL, GetPopupURL would incorrectly return the
123   // default URL.
124   SetValue(&popup_url_, tab_id, url);
125 }
126
127 bool ExtensionAction::HasPopup(int tab_id) const {
128   return !GetPopupUrl(tab_id).is_empty();
129 }
130
131 GURL ExtensionAction::GetPopupUrl(int tab_id) const {
132   return GetValue(&popup_url_, tab_id);
133 }
134
135 void ExtensionAction::SetIcon(int tab_id, const gfx::Image& image) {
136   SetValue(&icon_, tab_id, image.AsImageSkia());
137 }
138
139 gfx::ImageSkia ExtensionAction::GetExplicitlySetIcon(int tab_id) const {
140   return GetValue(&icon_, tab_id);
141 }
142
143 bool ExtensionAction::SetIsVisible(int tab_id, bool new_visibility) {
144   const bool old_visibility = GetValue(&is_visible_, tab_id);
145
146   if (old_visibility == new_visibility)
147     return false;
148
149   SetValue(&is_visible_, tab_id, new_visibility);
150
151   return true;
152 }
153
154 void ExtensionAction::DeclarativeShow(int tab_id) {
155   DCHECK_NE(tab_id, kDefaultTabId);
156   ++declarative_show_count_[tab_id];  // Use default initialization to 0.
157 }
158
159 void ExtensionAction::UndoDeclarativeShow(int tab_id) {
160   int& show_count = declarative_show_count_[tab_id];
161   DCHECK_GT(show_count, 0);
162   if (--show_count == 0)
163     declarative_show_count_.erase(tab_id);
164 }
165
166 void ExtensionAction::ClearAllValuesForTab(int tab_id) {
167   popup_url_.erase(tab_id);
168   title_.erase(tab_id);
169   icon_.erase(tab_id);
170   badge_text_.erase(tab_id);
171   badge_text_color_.erase(tab_id);
172   badge_background_color_.erase(tab_id);
173   is_visible_.erase(tab_id);
174   // TODO(jyasskin): Erase the element from declarative_show_count_
175   // when the tab's closed.  There's a race between the
176   // PageActionController and the ContentRulesRegistry on navigation,
177   // which prevents me from cleaning everything up now.
178 }
179
180 void ExtensionAction::PaintBadge(gfx::Canvas* canvas,
181                                  const gfx::Rect& bounds,
182                                  int tab_id) {
183   badge_util::PaintBadge(
184       canvas,
185       bounds,
186       GetBadgeText(tab_id),
187       GetBadgeTextColor(tab_id),
188       GetBadgeBackgroundColor(tab_id),
189       GetIconWidth(tab_id),
190       action_type());
191 }
192
193 gfx::ImageSkia ExtensionAction::GetIconWithBadge(
194     const gfx::ImageSkia& icon,
195     int tab_id,
196     const gfx::Size& spacing) const {
197   if (tab_id < 0)
198     return icon;
199
200   return gfx::ImageSkia(
201       new IconWithBadgeImageSource(icon,
202                                    icon.size(),
203                                    spacing,
204                                    GetBadgeText(tab_id),
205                                    GetBadgeTextColor(tab_id),
206                                    GetBadgeBackgroundColor(tab_id),
207                                    action_type()),
208      icon.size());
209 }
210
211 bool ExtensionAction::HasPopupUrl(int tab_id) const {
212   return HasValue(popup_url_, tab_id);
213 }
214
215 bool ExtensionAction::HasTitle(int tab_id) const {
216   return HasValue(title_, tab_id);
217 }
218
219 bool ExtensionAction::HasBadgeText(int tab_id) const {
220   return HasValue(badge_text_, tab_id);
221 }
222
223 bool ExtensionAction::HasBadgeBackgroundColor(int tab_id) const {
224   return HasValue(badge_background_color_, tab_id);
225 }
226
227 bool ExtensionAction::HasBadgeTextColor(int tab_id) const {
228   return HasValue(badge_text_color_, tab_id);
229 }
230
231 bool ExtensionAction::HasIsVisible(int tab_id) const {
232   return HasValue(is_visible_, tab_id);
233 }
234
235 bool ExtensionAction::HasIcon(int tab_id) const {
236   return HasValue(icon_, tab_id);
237 }
238
239 // Determines which icon would be returned by |GetIcon|, and returns its width.
240 int ExtensionAction::GetIconWidth(int tab_id) const {
241   // If icon has been set, return its width.
242   gfx::ImageSkia icon = GetValue(&icon_, tab_id);
243   if (!icon.isNull())
244     return icon.width();
245   // If there is a default icon, the icon width will be set depending on our
246   // action type.
247   if (default_icon_)
248     return GetIconSizeForType(action_type());
249
250   // If no icon has been set and there is no default icon, we need favicon
251   // width.
252   return ui::ResourceBundle::GetSharedInstance().GetImageNamed(
253           IDR_EXTENSIONS_FAVICON).ToImageSkia()->width();
254 }