// Copyright (c) 2011 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/extensions/extension_page_actions_module.h" #include <string> #include "base/string_number_conversions.h" #include "chrome/browser/extensions/extension_page_actions_module_constants.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_tab_helper.h" #include "chrome/browser/extensions/extension_tabs_module.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" #include "chrome/common/extensions/extension.h" #include "chrome/common/extensions/extension_action.h" #include "chrome/common/extensions/extension_error_utils.h" #include "chrome/common/render_messages.h" #include "content/browser/tab_contents/navigation_entry.h" #include "content/browser/tab_contents/tab_contents.h" namespace keys = extension_page_actions_module_constants; namespace { // Errors. const char kNoTabError[] = "No tab with id: *."; const char kNoPageActionError[] = "This extension has no page action specified."; const char kUrlNotActiveError[] = "This url is no longer active: *."; const char kIconIndexOutOfBounds[] = "Page action icon index out of bounds."; const char kNoIconSpecified[] = "Page action has no icons to show."; } // TODO(EXTENSIONS_DEPRECATED): obsolete API. bool PageActionFunction::SetPageActionEnabled(bool enable) { std::string page_action_id; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &page_action_id)); DictionaryValue* action; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(1, &action)); int tab_id; EXTENSION_FUNCTION_VALIDATE(action->GetInteger(keys::kTabIdKey, &tab_id)); std::string url; EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kUrlKey, &url)); std::string title; int icon_id = 0; if (enable) { // Both of those are optional. if (action->HasKey(keys::kTitleKey)) EXTENSION_FUNCTION_VALIDATE(action->GetString(keys::kTitleKey, &title)); if (action->HasKey(keys::kIconIdKey)) { EXTENSION_FUNCTION_VALIDATE(action->GetInteger(keys::kIconIdKey, &icon_id)); } } ExtensionAction* page_action = GetExtension()->page_action(); if (!page_action) { error_ = kNoPageActionError; return false; } if (icon_id < 0 || static_cast<size_t>(icon_id) >= page_action->icon_paths()->size()) { error_ = (icon_id == 0) ? kNoIconSpecified : kIconIndexOutOfBounds; return false; } // Find the TabContents that contains this tab id. TabContentsWrapper* contents = NULL; bool result = ExtensionTabUtil::GetTabById( tab_id, profile(), include_incognito(), NULL, NULL, &contents, NULL); if (!result || !contents) { error_ = ExtensionErrorUtils::FormatErrorMessage( kNoTabError, base::IntToString(tab_id)); return false; } // Make sure the URL hasn't changed. NavigationEntry* entry = contents->controller().GetActiveEntry(); if (!entry || url != entry->url().spec()) { error_ = ExtensionErrorUtils::FormatErrorMessage(kUrlNotActiveError, url); return false; } // Set visibility and broadcast notifications that the UI should be updated. page_action->SetIsVisible(tab_id, enable); page_action->SetTitle(tab_id, title); page_action->SetIconIndex(tab_id, icon_id); contents->extension_tab_helper()->PageActionStateChanged(); return true; } bool PageActionFunction::InitCommon(int tab_id) { page_action_ = GetExtension()->page_action(); if (!page_action_) { error_ = kNoPageActionError; return false; } // Find the TabContents that contains this tab id. contents_ = NULL; TabContentsWrapper* wrapper = NULL; bool result = ExtensionTabUtil::GetTabById( tab_id, profile(), include_incognito(), NULL, NULL, &wrapper, NULL); if (!result || !wrapper) { error_ = ExtensionErrorUtils::FormatErrorMessage( kNoTabError, base::IntToString(tab_id)); return false; } contents_ = wrapper; return true; } bool PageActionFunction::SetVisible(bool visible) { int tab_id; EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id)); if (!InitCommon(tab_id)) return false; page_action_->SetIsVisible(tab_id, visible); contents_->extension_tab_helper()->PageActionStateChanged(); return true; } bool EnablePageActionFunction::RunImpl() { return SetPageActionEnabled(true); } bool DisablePageActionFunction::RunImpl() { return SetPageActionEnabled(false); } bool PageActionShowFunction::RunImpl() { return SetVisible(true); } bool PageActionHideFunction::RunImpl() { return SetVisible(false); } bool PageActionSetIconFunction::RunImpl() { DictionaryValue* args; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); int tab_id; EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id)); if (!InitCommon(tab_id)) return false; // setIcon can take a variant argument: either a canvas ImageData, or an // icon index. BinaryValue* binary; int icon_index; if (args->GetBinary("imageData", &binary)) { IPC::Message bitmap_pickle(binary->GetBuffer(), binary->GetSize()); void* iter = NULL; scoped_ptr<SkBitmap> bitmap(new SkBitmap); EXTENSION_FUNCTION_VALIDATE( IPC::ReadParam(&bitmap_pickle, &iter, bitmap.get())); page_action_->SetIcon(tab_id, *bitmap); } else if (args->GetInteger("iconIndex", &icon_index)) { if (icon_index < 0 || static_cast<size_t>(icon_index) >= page_action_->icon_paths()->size()) { error_ = kIconIndexOutOfBounds; return false; } page_action_->SetIcon(tab_id, SkBitmap()); page_action_->SetIconIndex(tab_id, icon_index); } else { EXTENSION_FUNCTION_VALIDATE(false); } contents_->extension_tab_helper()->PageActionStateChanged(); return true; } bool PageActionSetTitleFunction::RunImpl() { DictionaryValue* args; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); int tab_id; EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id)); if (!InitCommon(tab_id)) return false; std::string title; EXTENSION_FUNCTION_VALIDATE(args->GetString("title", &title)); page_action_->SetTitle(tab_id, title); contents_->extension_tab_helper()->PageActionStateChanged(); return true; } bool PageActionSetPopupFunction::RunImpl() { DictionaryValue* args; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); int tab_id; EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id)); if (!InitCommon(tab_id)) return false; // TODO(skerner): Consider allowing null and undefined to mean the popup // should be removed. std::string popup_string; EXTENSION_FUNCTION_VALIDATE(args->GetString("popup", &popup_string)); GURL popup_url; if (!popup_string.empty()) popup_url = GetExtension()->GetResourceURL(popup_string); page_action_->SetPopupUrl(tab_id, popup_url); contents_->extension_tab_helper()->PageActionStateChanged(); return true; } // Not currently exposed to extensions. To re-enable, add mapping in // extension_function_dispatcher. bool PageActionSetBadgeBackgroundColorFunction::RunImpl() { DictionaryValue* args; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); int tab_id; EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id)); if (!InitCommon(tab_id)) return false; ListValue* color_value; EXTENSION_FUNCTION_VALIDATE(args->GetList("color", &color_value)); EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4); int color_array[4] = {0}; for (size_t i = 0; i < arraysize(color_array); ++i) EXTENSION_FUNCTION_VALIDATE(color_value->GetInteger(i, &color_array[i])); SkColor color = SkColorSetARGB(color_array[3], color_array[0], color_array[1], color_array[2]); page_action_->SetBadgeBackgroundColor(tab_id, color); contents_->extension_tab_helper()->PageActionStateChanged(); return true; } // Not currently exposed to extensions. To re-enable, add mapping in // extension_function_dispatcher. bool PageActionSetBadgeTextColorFunction::RunImpl() { DictionaryValue* args; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); int tab_id; EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id)); if (!InitCommon(tab_id)) return false; ListValue* color_value; EXTENSION_FUNCTION_VALIDATE(args->GetList("color", &color_value)); EXTENSION_FUNCTION_VALIDATE(color_value->GetSize() == 4); int color_array[4] = {0}; for (size_t i = 0; i < arraysize(color_array); ++i) EXTENSION_FUNCTION_VALIDATE(color_value->GetInteger(i, &color_array[i])); SkColor color = SkColorSetARGB(color_array[3], color_array[0], color_array[1], color_array[2]); page_action_->SetBadgeTextColor(tab_id, color); contents_->extension_tab_helper()->PageActionStateChanged(); return true; } // Not currently exposed to extensions. To re-enable, add mapping in // extension_function_dispatcher. bool PageActionSetBadgeTextFunction::RunImpl() { DictionaryValue* args; EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &args)); int tab_id; EXTENSION_FUNCTION_VALIDATE(args->GetInteger("tabId", &tab_id)); if (!InitCommon(tab_id)) return false; std::string text; EXTENSION_FUNCTION_VALIDATE(args->GetString("text", &text)); page_action_->SetBadgeText(tab_id, text); contents_->extension_tab_helper()->PageActionStateChanged(); return true; }