Commit 1e1bbdec authored by rockot's avatar rockot Committed by Commit bot

Add ChromeExtensionFunctionDetails

In the interest of phasing out the totally unnecessary
*Chrome*ExtensionFunction base classes, this establishes a
ChromeExtensionFunctionDetails object which can be created
by extension function implementations in //chrome who need
access to Chrome-specific details.

This object can be very easily composed into such function
implementations such that they can move away from using
e.g. ChromeAsyncExtensionFunction or
ChromeUIThreadExtensionFunction as a base class and instead
rely on more universal and generic ExtensionFunction and its
immediate derivatives.

A conversion of the tabs API ExecuteCodeInTabFunction is
included for demonstration purposes.

BUG=None
R=scheib@chromium.org
CC=lfg@chromium.org

Review URL: https://codereview.chromium.org/543873002

Cr-Commit-Position: refs/heads/master@{#293570}
parent 6a55df7b
......@@ -5,8 +5,8 @@
#ifndef CHROME_BROWSER_EXTENSIONS_API_EXECUTE_CODE_FUNCTION_H_
#define CHROME_BROWSER_EXTENSIONS_API_EXECUTE_CODE_FUNCTION_H_
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/common/extensions/api/tabs.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/script_executor.h"
namespace extensions {
......@@ -14,7 +14,7 @@ namespace extensions {
// Base class for javascript code injection.
// This is used by both chrome.webview.executeScript and
// chrome.tabs.executeScript.
class ExecuteCodeFunction : public ChromeAsyncExtensionFunction {
class ExecuteCodeFunction : public AsyncExtensionFunction {
public:
ExecuteCodeFunction();
......
......@@ -1636,7 +1636,7 @@ void TabsDetectLanguageFunction::GotLanguage(const std::string& language) {
}
ExecuteCodeInTabFunction::ExecuteCodeInTabFunction()
: execute_tab_id_(-1) {
: chrome_details_(this), execute_tab_id_(-1) {
}
ExecuteCodeInTabFunction::~ExecuteCodeInTabFunction() {}
......@@ -1650,6 +1650,39 @@ bool ExecuteCodeInTabFunction::HasPermission() {
return ExtensionFunction::HasPermission();
}
bool ExecuteCodeInTabFunction::Init() {
if (details_.get())
return true;
// |tab_id| is optional so it's ok if it's not there.
int tab_id = -1;
if (args_->GetInteger(0, &tab_id))
EXTENSION_FUNCTION_VALIDATE(tab_id >= 0);
// |details| are not optional.
base::DictionaryValue* details_value = NULL;
if (!args_->GetDictionary(1, &details_value))
return false;
scoped_ptr<InjectDetails> details(new InjectDetails());
if (!InjectDetails::Populate(*details_value, details.get()))
return false;
// If the tab ID wasn't given then it needs to be converted to the
// currently active tab's ID.
if (tab_id == -1) {
Browser* browser = chrome_details_.GetCurrentBrowser();
if (!browser)
return false;
content::WebContents* web_contents = NULL;
if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
return false;
}
execute_tab_id_ = tab_id;
details_ = details.Pass();
return true;
}
bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage() {
content::WebContents* contents = NULL;
......@@ -1657,7 +1690,7 @@ bool ExecuteCodeInTabFunction::CanExecuteScriptOnPage() {
// tab in the current window.
CHECK_GE(execute_tab_id_, 0);
if (!GetTabById(execute_tab_id_,
GetProfile(),
chrome_details_.GetProfile(),
include_incognito(),
NULL,
NULL,
......@@ -1690,7 +1723,7 @@ ScriptExecutor* ExecuteCodeInTabFunction::GetScriptExecutor() {
content::WebContents* contents = NULL;
bool success = GetTabById(execute_tab_id_,
GetProfile(),
chrome_details_.GetProfile(),
include_incognito(),
&browser,
NULL,
......@@ -1726,39 +1759,6 @@ void TabsExecuteScriptFunction::OnExecuteCodeFinished(
ExecuteCodeInTabFunction::OnExecuteCodeFinished(error, on_url, result);
}
bool ExecuteCodeInTabFunction::Init() {
if (details_.get())
return true;
// |tab_id| is optional so it's ok if it's not there.
int tab_id = -1;
if (args_->GetInteger(0, &tab_id))
EXTENSION_FUNCTION_VALIDATE(tab_id >= 0);
// |details| are not optional.
base::DictionaryValue* details_value = NULL;
if (!args_->GetDictionary(1, &details_value))
return false;
scoped_ptr<InjectDetails> details(new InjectDetails());
if (!InjectDetails::Populate(*details_value, details.get()))
return false;
// If the tab ID wasn't given then it needs to be converted to the
// currently active tab's ID.
if (tab_id == -1) {
Browser* browser = GetCurrentBrowser();
if (!browser)
return false;
content::WebContents* web_contents = NULL;
if (!ExtensionTabUtil::GetDefaultTab(browser, &web_contents, &tab_id))
return false;
}
execute_tab_id_ = tab_id;
details_ = details.Pass();
return true;
}
bool TabsInsertCSSFunction::ShouldInsertCSS() const {
return true;
}
......
......@@ -11,6 +11,7 @@
#include "base/compiler_specific.h"
#include "chrome/browser/extensions/api/execute_code_function.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/browser/ui/zoom/zoom_controller.h"
#include "chrome/common/extensions/api/tabs.h"
#include "content/public/browser/notification_observer.h"
......@@ -232,6 +233,8 @@ class ExecuteCodeInTabFunction : public ExecuteCodeFunction {
virtual const GURL& GetWebViewSrc() const OVERRIDE;
private:
const ChromeExtensionFunctionDetails chrome_details_;
// Id of tab which executes code.
int execute_tab_id_;
};
......
......@@ -7,6 +7,7 @@
#include "base/strings/string_number_conversions.h"
#include "chrome/browser/extensions/api/tabs/tabs_constants.h"
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/extensions/window_controller_list.h"
#include "extensions/browser/extension_function_dispatcher.h"
......@@ -18,6 +19,7 @@ namespace windows_util {
bool GetWindowFromWindowID(ChromeUIThreadExtensionFunction* function,
int window_id,
extensions::WindowController** controller) {
ChromeExtensionFunctionDetails function_details(function);
if (window_id == extension_misc::kCurrentWindowId) {
extensions::WindowController* extension_window_controller =
function->dispatcher()->delegate()->GetExtensionWindowController();
......@@ -26,16 +28,16 @@ bool GetWindowFromWindowID(ChromeUIThreadExtensionFunction* function,
*controller = extension_window_controller;
} else {
// Otherwise get the focused or most recently added window.
*controller = extensions::WindowControllerList::GetInstance()->
CurrentWindowForFunction(function);
*controller = extensions::WindowControllerList::GetInstance()
->CurrentWindowForFunction(function_details);
}
if (!(*controller)) {
function->SetError(extensions::tabs_constants::kNoCurrentWindowError);
return false;
}
} else {
*controller = extensions::WindowControllerList::GetInstance()->
FindWindowForFunctionById(function, window_id);
*controller = extensions::WindowControllerList::GetInstance()
->FindWindowForFunctionById(function_details, window_id);
if (!(*controller)) {
function->SetError(extensions::ErrorUtils::FormatErrorMessage(
extensions::tabs_constants::kWindowNotFoundError,
......
......@@ -4,6 +4,7 @@
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/extensions/window_controller_list.h"
#include "chrome/browser/profiles/profile.h"
......@@ -92,7 +93,7 @@ ChromeUIThreadExtensionFunction::GetExtensionWindowController() {
}
return extensions::WindowControllerList::GetInstance()
->CurrentWindowForFunction(this);
->CurrentWindowForFunction(ChromeExtensionFunctionDetails(this));
}
content::WebContents*
......
......@@ -20,6 +20,10 @@ class WindowController;
// A chrome specific analog to AsyncExtensionFunction. This has access to a
// chrome Profile.
//
// DEPRECATED: Please consider inherting UIThreadExtensionFunction directly.
// Then if you need access to Chrome details, you can construct a
// ChromeExtensionFunctionDetails object within your function implementation.
class ChromeUIThreadExtensionFunction : public UIThreadExtensionFunction {
public:
ChromeUIThreadExtensionFunction();
......@@ -64,6 +68,11 @@ class ChromeUIThreadExtensionFunction : public UIThreadExtensionFunction {
// A chrome specific analog to AsyncExtensionFunction. This has access to a
// chrome Profile.
//
// DEPRECATED: Please consider inherting UIThreadExtensionFunction or
// AsyncExtensionFunction directly. Then if you need access to Chrome details,
// you can construct a ChromeExtensionFunctionDetails object within your
// function implementation.
class ChromeAsyncExtensionFunction : public ChromeUIThreadExtensionFunction {
public:
ChromeAsyncExtensionFunction();
......@@ -83,6 +92,11 @@ class ChromeAsyncExtensionFunction : public ChromeUIThreadExtensionFunction {
// A chrome specific analog to SyncExtensionFunction. This has access to a
// chrome Profile.
//
// DEPRECATED: Please consider inherting UIThreadExtensionFunction or
// SyncExtensionFunction directly. Then if you need access to Chrome details,
// you can construct a ChromeExtensionFunctionDetails object within your
// function implementation.
class ChromeSyncExtensionFunction : public ChromeUIThreadExtensionFunction {
public:
ChromeSyncExtensionFunction();
......
// Copyright 2014 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/chrome_extension_function_details.h"
#include "chrome/browser/extensions/window_controller.h"
#include "chrome/browser/extensions/window_controller_list.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/browser/render_view_host.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_function_dispatcher.h"
using content::WebContents;
using content::RenderViewHost;
using extensions::WindowController;
ChromeExtensionFunctionDetails::ChromeExtensionFunctionDetails(
UIThreadExtensionFunction* function)
: function_(function) {
}
ChromeExtensionFunctionDetails::~ChromeExtensionFunctionDetails() {
}
Profile* ChromeExtensionFunctionDetails::GetProfile() const {
return Profile::FromBrowserContext(function_->browser_context());
}
bool ChromeExtensionFunctionDetails::CanOperateOnWindow(
const extensions::WindowController* window_controller) const {
// |extension()| is NULL for unit tests only.
if (function_->extension() != NULL &&
!window_controller->IsVisibleToExtension(function_->extension())) {
return false;
}
if (GetProfile() == window_controller->profile())
return true;
if (!function_->include_incognito())
return false;
return GetProfile()->HasOffTheRecordProfile() &&
GetProfile()->GetOffTheRecordProfile() == window_controller->profile();
}
// TODO(stevenjb): Replace this with GetExtensionWindowController().
Browser* ChromeExtensionFunctionDetails::GetCurrentBrowser() const {
// If the delegate has an associated browser, return it.
if (function_->dispatcher()) {
extensions::WindowController* window_controller =
function_->dispatcher()->delegate()->GetExtensionWindowController();
if (window_controller) {
Browser* browser = window_controller->GetBrowser();
if (browser)
return browser;
}
}
// Otherwise, try to default to a reasonable browser. If |include_incognito_|
// is true, we will also search browsers in the incognito version of this
// profile. Note that the profile may already be incognito, in which case
// we will search the incognito version only, regardless of the value of
// |include_incognito|. Look only for browsers on the active desktop as it is
// preferable to pretend no browser is open then to return a browser on
// another desktop.
if (function_->render_view_host()) {
Profile* profile = Profile::FromBrowserContext(
function_->render_view_host()->GetProcess()->GetBrowserContext());
Browser* browser = chrome::FindAnyBrowser(
profile, function_->include_incognito(), chrome::GetActiveDesktop());
if (browser)
return browser;
}
// NOTE(rafaelw): This can return NULL in some circumstances. In particular,
// a background_page onload chrome.tabs api call can make it into here
// before the browser is sufficiently initialized to return here, or
// all of this profile's browser windows may have been closed.
// A similar situation may arise during shutdown.
// TODO(rafaelw): Delay creation of background_page until the browser
// is available. http://code.google.com/p/chromium/issues/detail?id=13284
return NULL;
}
extensions::WindowController*
ChromeExtensionFunctionDetails::GetExtensionWindowController() const {
// If the delegate has an associated window controller, return it.
if (function_->dispatcher()) {
extensions::WindowController* window_controller =
function_->dispatcher()->delegate()->GetExtensionWindowController();
if (window_controller)
return window_controller;
}
return extensions::WindowControllerList::GetInstance()
->CurrentWindowForFunction(*this);
}
content::WebContents*
ChromeExtensionFunctionDetails::GetAssociatedWebContents() {
content::WebContents* web_contents = function_->GetAssociatedWebContents();
if (web_contents)
return web_contents;
Browser* browser = GetCurrentBrowser();
if (!browser)
return NULL;
return browser->tab_strip_model()->GetActiveWebContents();
}
// Copyright 2014 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.
#ifndef CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_FUNCTION_DETAILS_H_
#define CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_FUNCTION_DETAILS_H_
#include "base/macros.h"
class Browser;
class Profile;
class UIThreadExtensionFunction;
namespace content {
class WebContents;
}
namespace extensions {
class WindowController;
} // namespace extensions
// Provides Chrome-specific details to UIThreadExtensionFunction
// implementations.
class ChromeExtensionFunctionDetails {
public:
// Constructs a new ChromeExtensionFunctionDetails instance for |function|.
// This instance does not own |function| and must outlive it.
explicit ChromeExtensionFunctionDetails(UIThreadExtensionFunction* function);
~ChromeExtensionFunctionDetails();
Profile* GetProfile() const;
// Returns true if this function (and the profile and extension that it was
// invoked from) can operate on the window wrapped by |window_controller|.
bool CanOperateOnWindow(
const extensions::WindowController* window_controller) const;
// Gets the "current" browser, if any.
//
// Many extension APIs operate relative to the current browser, which is the
// browser the calling code is running inside of. For example, popups, tabs,
// and infobars all have a containing browser, but background pages and
// notification bubbles do not.
//
// If there is no containing window, the current browser defaults to the
// foremost one.
//
// Incognito browsers are not considered unless the calling extension has
// incognito access enabled.
//
// This method can return NULL if there is no matching browser, which can
// happen if only incognito windows are open, or early in startup or shutdown
// shutdown when there are no active windows.
//
// TODO(stevenjb): Replace this with GetExtensionWindowController().
Browser* GetCurrentBrowser() const;
// Same as above but uses WindowControllerList instead of BrowserList.
extensions::WindowController* GetExtensionWindowController() const;
// Gets the "current" web contents if any. If there is no associated web
// contents then defaults to the foremost one.
content::WebContents* GetAssociatedWebContents();
private:
// The function for which these details have been created. Must outlive the
// ChromeExtensionFunctionDetails instance.
UIThreadExtensionFunction* function_;
DISALLOW_COPY_AND_ASSIGN(ChromeExtensionFunctionDetails);
};
#endif // CHROME_BROWSER_EXTENSIONS_CHROME_EXTENSION_FUNCTION_DETAILS_H_
......@@ -6,7 +6,7 @@
#include <algorithm>
#include "chrome/browser/extensions/chrome_extension_function.h"
#include "chrome/browser/extensions/chrome_extension_function_details.h"
#include "chrome/browser/extensions/window_controller_list_observer.h"
#include "components/sessions/session_id.h"
#include "ui/base/base_window.h"
......@@ -62,21 +62,21 @@ WindowController* WindowControllerList::FindWindowById(int id) const {
}
WindowController* WindowControllerList::FindWindowForFunctionById(
const ChromeUIThreadExtensionFunction* function,
const ChromeExtensionFunctionDetails& function_details,
int id) const {
WindowController* controller = FindWindowById(id);
if (controller && function->CanOperateOnWindow(controller))
if (controller && function_details.CanOperateOnWindow(controller))
return controller;
return NULL;
}
WindowController* WindowControllerList::CurrentWindowForFunction(
const ChromeUIThreadExtensionFunction* function) const {
const ChromeExtensionFunctionDetails& function_details) const {
WindowController* result = NULL;
// Returns either the focused window (if any), or the last window in the list.
for (ControllerList::const_iterator iter = windows().begin();
iter != windows().end(); ++iter) {
if (function->CanOperateOnWindow(*iter)) {
if (function_details.CanOperateOnWindow(*iter)) {
result = *iter;
if (result->window()->IsActive())
break; // use focused window
......
......@@ -13,7 +13,7 @@
#include "chrome/browser/extensions/window_controller.h"
class Profile;
class ChromeUIThreadExtensionFunction;
class ChromeExtensionFunctionDetails;
namespace extensions {
......@@ -38,13 +38,13 @@ class WindowControllerList {
// Returns a window matching the context the function was invoked in.
WindowController* FindWindowForFunctionById(
const ChromeUIThreadExtensionFunction* function,
const ChromeExtensionFunctionDetails& function_details,
int id) const;
// Returns the focused or last added window matching the context the function
// was invoked in.
WindowController* CurrentWindowForFunction(
const ChromeUIThreadExtensionFunction* function) const;
const ChromeExtensionFunctionDetails& function_details) const;
const ControllerList& windows() const { return windows_; }
......
......@@ -562,6 +562,8 @@
'browser/extensions/chrome_content_browser_client_extensions_part.h',
'browser/extensions/chrome_extension_function.cc',
'browser/extensions/chrome_extension_function.h',
'browser/extensions/chrome_extension_function_details.cc',
'browser/extensions/chrome_extension_function_details.h',
'browser/extensions/chrome_extension_host_delegate.cc',
'browser/extensions/chrome_extension_host_delegate.h',
'browser/extensions/chrome_extension_web_contents_observer.cc',
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment