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