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 24 namespace keys = extension_page_actions_module_constants; 25 26 namespace { 27 // Errors. 28 const char kNoTabError[] = "No tab with id: *."; 29 const char kNoPageActionError[] = 30 "This extension has no page action specified."; 31 const char kUrlNotActiveError[] = "This url is no longer active: *."; 32 const char kIconIndexOutOfBounds[] = "Page action icon index out of bounds."; 33 const char kNoIconSpecified[] = "Page action has no icons to show."; 34 } 35 36 // TODO(EXTENSIONS_DEPRECATED): obsolete API. 37 bool 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 98 bool 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 120 bool 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 131 bool EnablePageActionFunction::RunImpl() { 132 return SetPageActionEnabled(true); 133 } 134 135 bool DisablePageActionFunction::RunImpl() { 136 return SetPageActionEnabled(false); 137 } 138 139 bool PageActionShowFunction::RunImpl() { 140 return SetVisible(true); 141 } 142 143 bool PageActionHideFunction::RunImpl() { 144 return SetVisible(false); 145 } 146 147 bool 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 183 bool 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 200 bool 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. 225 bool 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. 251 bool 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. 277 bool 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