extension_page_actions_module.cc revision 21d179b334e59e9a3bfcaed4c4430bef1bc5759d
1// Copyright (c) 2010 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_page_actions_module.h"
6
7#include "base/string_number_conversions.h"
8#include "chrome/browser/browser_list.h"
9#include "chrome/browser/extensions/extension_page_actions_module_constants.h"
10#include "chrome/browser/extensions/extension_tabs_module.h"
11#include "chrome/browser/extensions/extension_service.h"
12#include "chrome/browser/profiles/profile.h"
13#include "chrome/browser/tab_contents/navigation_entry.h"
14#include "chrome/browser/tab_contents/tab_contents.h"
15#include "chrome/browser/ui/browser.h"
16#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
17#include "chrome/common/extensions/extension.h"
18#include "chrome/common/extensions/extension_action.h"
19#include "chrome/common/extensions/extension_error_utils.h"
20#include "chrome/common/render_messages.h"
21
22namespace keys = extension_page_actions_module_constants;
23
24namespace {
25// Errors.
26const char kNoTabError[] = "No tab with id: *.";
27const char kNoPageActionError[] =
28    "This extension has no page action specified.";
29const char kUrlNotActiveError[] = "This url is no longer active: *.";
30const char kIconIndexOutOfBounds[] = "Page action icon index out of bounds.";
31const char kNoIconSpecified[] = "Page action has no icons to show.";
32}
33
34// TODO(EXTENSIONS_DEPRECATED): obsolete API.
35bool PageActionFunction::SetPageActionEnabled(bool enable) {
36  std::string page_action_id;
37  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &page_action_id));
38  DictionaryValue* action;
39  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &action));
40
41  int tab_id;
42  EXTENSION_FUNCTION_VALIDATE(action->GetInteger(keys::kTabIdKey, &tab_id));
43  std::string url;
44  EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kUrlKey, &url));
45
46  std::string title;
47  int icon_id = 0;
48  if (enable) {
49    // Both of those are optional.
50    if (action->HasKey(keys::kTitleKey))
51      EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kTitleKey, &title));
52    if (action->HasKey(keys::kIconIdKey)) {
53      EXTENSION_FUNCTION_VALIDATE(action->GetInteger(keys::kIconIdKey,
54                                                     &icon_id));
55    }
56  }
57
58  ExtensionAction* page_action = GetExtension()->page_action();
59  if (!page_action) {
60    error_ = kNoPageActionError;
61    return false;
62  }
63
64  if (icon_id < 0 ||
65      static_cast<size_t>(icon_id) >= page_action->icon_paths()->size()) {
66    error_ = (icon_id == 0) ? kNoIconSpecified : kIconIndexOutOfBounds;
67    return false;
68  }
69
70  // Find the TabContents that contains this tab id.
71  TabContentsWrapper* contents = NULL;
72  bool result = ExtensionTabUtil::GetTabById(
73      tab_id, profile(), include_incognito(), NULL, NULL, &contents, NULL);
74  if (!result || !contents) {
75    error_ = ExtensionErrorUtils::FormatErrorMessage(
76        kNoTabError, base::IntToString(tab_id));
77    return false;
78  }
79
80  // Make sure the URL hasn't changed.
81  NavigationEntry* entry = contents->controller().GetActiveEntry();
82  if (!entry || url != entry->url().spec()) {
83    error_ = ExtensionErrorUtils::FormatErrorMessage(kUrlNotActiveError, url);
84    return false;
85  }
86
87  // Set visibility and broadcast notifications that the UI should be updated.
88  page_action->SetIsVisible(tab_id, enable);
89  page_action->SetTitle(tab_id, title);
90  page_action->SetIconIndex(tab_id, icon_id);
91  contents->tab_contents()->PageActionStateChanged();
92
93  return true;
94}
95
96bool PageActionFunction::InitCommon(int tab_id) {
97  page_action_ = GetExtension()->page_action();
98  if (!page_action_) {
99    error_ = kNoPageActionError;
100    return false;
101  }
102
103  // Find the TabContents that contains this tab id.
104  contents_ = NULL;
105  TabContentsWrapper* wrapper = NULL;
106  bool result = ExtensionTabUtil::GetTabById(
107      tab_id, profile(), include_incognito(), NULL, NULL, &wrapper, NULL);
108  if (!result || !wrapper) {
109    error_ = ExtensionErrorUtils::FormatErrorMessage(
110        kNoTabError, base::IntToString(tab_id));
111    return false;
112  }
113  contents_ = wrapper->tab_contents();
114
115  return true;
116}
117
118bool PageActionFunction::SetVisible(bool visible) {
119  int tab_id;
120  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
121  if (!InitCommon(tab_id))
122    return false;
123
124  page_action_->SetIsVisible(tab_id, visible);
125  contents_->PageActionStateChanged();
126  return true;
127}
128
129bool EnablePageActionFunction::RunImpl() {
130  return SetPageActionEnabled(true);
131}
132
133bool DisablePageActionFunction::RunImpl() {
134  return SetPageActionEnabled(false);
135}
136
137bool PageActionShowFunction::RunImpl() {
138  return SetVisible(true);
139}
140
141bool PageActionHideFunction::RunImpl() {
142  return SetVisible(false);
143}
144
145bool PageActionSetIconFunction::RunImpl() {
146  DictionaryValue* args;
147  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
148
149  int tab_id;
150  EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
151  if (!InitCommon(tab_id))
152    return false;
153
154  // setIcon can take a variant argument: either a canvas ImageData, or an
155  // icon index.
156  BinaryValue* binary;
157  int icon_index;
158  if (args->GetBinary("imageData", &binary)) {
159    IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize());
160    void* iter = NULL;
161    scoped_ptr<SkBitmap> bitmap(new SkBitmap);
162    EXTENSION_FUNCTION_VALIDATE(
163        IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get()));
164    page_action_->SetIcon(tab_id, *bitmap);
165  } else if (args->GetInteger("iconIndex", &icon_index)) {
166    if (icon_index < 0 || static_cast<size_t>(icon_index) >=
167                              page_action_->icon_paths()->size()) {
168      error_ = kIconIndexOutOfBounds;
169      return false;
170    }
171    page_action_->SetIcon(tab_id, SkBitmap());
172    page_action_->SetIconIndex(tab_id, icon_index);
173  } else {
174    EXTENSION_FUNCTION_VALIDATE(false);
175  }
176
177  contents_->PageActionStateChanged();
178  return true;
179}
180
181bool PageActionSetTitleFunction::RunImpl() {
182  DictionaryValue* args;
183  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
184
185  int tab_id;
186  EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
187  if (!InitCommon(tab_id))
188    return false;
189
190  std::string title;
191  EXTENSION_FUNCTION_VALIDATE(args->GetString("title", &title));
192
193  page_action_->SetTitle(tab_id, title);
194  contents_->PageActionStateChanged();
195  return true;
196}
197
198bool PageActionSetPopupFunction::RunImpl() {
199  DictionaryValue* args;
200  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
201
202  int tab_id;
203  EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
204  if (!InitCommon(tab_id))
205    return false;
206
207  // TODO(skerner): Consider allowing null and undefined to mean the popup
208  // should be removed.
209  std::string popup_string;
210  EXTENSION_FUNCTION_VALIDATE(args->GetString("popup", &popup_string));
211
212  GURL popup_url;
213  if (!popup_string.empty())
214    popup_url = GetExtension()->GetResourceURL(popup_string);
215
216  page_action_->SetPopupUrl(tab_id, popup_url);
217  contents_->PageActionStateChanged();
218  return true;
219}
220
221// Not currently exposed to extensions. To re-enable, add mapping in
222// extension_function_dispatcher.
223bool PageActionSetBadgeBackgroundColorFunction::RunImpl() {
224  DictionaryValue* args;
225  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
226
227  int tab_id;
228  EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
229  if (!InitCommon(tab_id))
230    return false;
231
232  ListValue* color_value;
233  EXTENSION_FUNCTION_VALIDATE(args->GetList("color", &color_value));
234  EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4);
235
236  int color_array[4] = {0};
237  for (size_t i = 0; i < arraysize(color_array); ++i)
238    EXTENSION_FUNCTION_VALIDATE(color_value->GetInteger(i, &color_array[i]));
239
240  SkColor color = SkColorSetARGB(color_array[3], color_array[0], color_array[1],
241                                 color_array[2]);
242  page_action_->SetBadgeBackgroundColor(tab_id, color);
243  contents_->PageActionStateChanged();
244  return true;
245}
246
247// Not currently exposed to extensions. To re-enable, add mapping in
248// extension_function_dispatcher.
249bool PageActionSetBadgeTextColorFunction::RunImpl() {
250  DictionaryValue* args;
251  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
252
253  int tab_id;
254  EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
255  if (!InitCommon(tab_id))
256    return false;
257
258  ListValue* color_value;
259  EXTENSION_FUNCTION_VALIDATE(args->GetList("color", &color_value));
260  EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4);
261
262  int color_array[4] = {0};
263  for (size_t i = 0; i < arraysize(color_array); ++i)
264    EXTENSION_FUNCTION_VALIDATE(color_value->GetInteger(i, &color_array[i]));
265
266  SkColor color = SkColorSetARGB(color_array[3], color_array[0], color_array[1],
267                                 color_array[2]);
268  page_action_->SetBadgeTextColor(tab_id, color);
269  contents_->PageActionStateChanged();
270  return true;
271}
272
273// Not currently exposed to extensions. To re-enable, add mapping in
274// extension_function_dispatcher.
275bool PageActionSetBadgeTextFunction::RunImpl() {
276  DictionaryValue* args;
277  EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args));
278
279  int tab_id;
280  EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id));
281  if (!InitCommon(tab_id))
282    return false;
283
284  std::string text;
285  EXTENSION_FUNCTION_VALIDATE(args->GetString("text", &text));
286
287  page_action_->SetBadgeText(tab_id, text);
288  contents_->PageActionStateChanged();
289  return true;
290}
291