blob: 12fde0b981f9818af5e2e58520567335a75aaf31 [file] [log] [blame]
// Copyright 2013 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 "content/shell/browser/shell.h"
#include "base/auto_reset.h"
#include "base/command_line.h"
#include "base/location.h"
#include "base/single_thread_task_runner.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h"
#include "base/thread_task_runner_handle.h"
#include "content/public/browser/devtools_agent_host.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_entry.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "content/public/common/content_switches.h"
#include "content/public/common/renderer_preferences.h"
#include "content/public/common/webrtc_ip_handling_policy.h"
#include "content/shell/browser/blink_test_controller.h"
#include "content/shell/browser/layout_test/layout_test_bluetooth_chooser_factory.h"
#include "content/shell/browser/layout_test/layout_test_devtools_frontend.h"
#include "content/shell/browser/layout_test/layout_test_javascript_dialog_manager.h"
#include "content/shell/browser/notify_done_forwarder.h"
#include "content/shell/browser/shell_browser_main_parts.h"
#include "content/shell/browser/shell_content_browser_client.h"
#include "content/shell/browser/shell_devtools_frontend.h"
#include "content/shell/browser/shell_javascript_dialog_manager.h"
#include "content/shell/common/shell_messages.h"
#include "content/shell/common/shell_switches.h"
namespace content {
const int kDefaultTestWindowWidthDip = 800;
const int kDefaultTestWindowHeightDip = 600;
std::vector<Shell*> Shell::windows_;
base::Callback<void(Shell*)> Shell::shell_created_callback_;
bool Shell::quit_message_loop_ = true;
class Shell::DevToolsWebContentsObserver : public WebContentsObserver {
public:
DevToolsWebContentsObserver(Shell* shell, WebContents* web_contents)
: WebContentsObserver(web_contents),
shell_(shell) {
}
// WebContentsObserver
void WebContentsDestroyed() override {
shell_->OnDevToolsWebContentsDestroyed();
}
private:
Shell* shell_;
DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
};
Shell::Shell(WebContents* web_contents)
: WebContentsObserver(web_contents),
devtools_frontend_(NULL),
is_fullscreen_(false),
window_(NULL),
#if defined(OS_MACOSX)
url_edit_view_(NULL),
#endif
headless_(false) {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kRunLayoutTest))
headless_ = true;
windows_.push_back(this);
if (!shell_created_callback_.is_null()) {
shell_created_callback_.Run(this);
shell_created_callback_.Reset();
}
}
Shell::~Shell() {
PlatformCleanUp();
for (size_t i = 0; i < windows_.size(); ++i) {
if (windows_[i] == this) {
windows_.erase(windows_.begin() + i);
break;
}
}
if (windows_.empty() && quit_message_loop_) {
if (headless_)
PlatformExit();
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE, base::MessageLoop::QuitWhenIdleClosure());
}
}
Shell* Shell::CreateShell(WebContents* web_contents,
const gfx::Size& initial_size) {
Shell* shell = new Shell(web_contents);
shell->PlatformCreateWindow(initial_size.width(), initial_size.height());
shell->web_contents_.reset(web_contents);
web_contents->SetDelegate(shell);
shell->PlatformSetContents();
shell->PlatformResizeSubViews();
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kRunLayoutTest)) {
web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
web_contents->GetRenderViewHost()->SyncRendererPrefs();
}
#if defined(ENABLE_WEBRTC)
if (command_line->HasSwitch(switches::kForceWebRtcIPHandlingPolicy)) {
web_contents->GetMutableRendererPrefs()->webrtc_ip_handling_policy =
command_line->GetSwitchValueASCII(
switches::kForceWebRtcIPHandlingPolicy);
}
#endif
return shell;
}
void Shell::CloseAllWindows() {
base::AutoReset<bool> auto_reset(&quit_message_loop_, false);
DevToolsAgentHost::DetachAllClients();
std::vector<Shell*> open_windows(windows_);
for (size_t i = 0; i < open_windows.size(); ++i)
open_windows[i]->Close();
base::MessageLoop::current()->RunUntilIdle();
PlatformExit();
}
void Shell::SetShellCreatedCallback(
base::Callback<void(Shell*)> shell_created_callback) {
DCHECK(shell_created_callback_.is_null());
shell_created_callback_ = shell_created_callback;
}
Shell* Shell::FromRenderViewHost(RenderViewHost* rvh) {
for (size_t i = 0; i < windows_.size(); ++i) {
if (windows_[i]->web_contents() &&
windows_[i]->web_contents()->GetRenderViewHost() == rvh) {
return windows_[i];
}
}
return NULL;
}
// static
void Shell::Initialize() {
PlatformInitialize(GetShellDefaultSize());
}
gfx::Size Shell::AdjustWindowSize(const gfx::Size& initial_size) {
if (!initial_size.IsEmpty())
return initial_size;
return GetShellDefaultSize();
}
Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
const GURL& url,
SiteInstance* site_instance,
const gfx::Size& initial_size) {
WebContents::CreateParams create_params(browser_context, site_instance);
create_params.initial_size = AdjustWindowSize(initial_size);
WebContents* web_contents = WebContents::Create(create_params);
Shell* shell = CreateShell(web_contents, create_params.initial_size);
if (!url.is_empty())
shell->LoadURL(url);
return shell;
}
void Shell::LoadURL(const GURL& url) {
LoadURLForFrame(url, std::string());
}
void Shell::LoadURLForFrame(const GURL& url, const std::string& frame_name) {
NavigationController::LoadURLParams params(url);
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
params.frame_name = frame_name;
web_contents_->GetController().LoadURLWithParams(params);
web_contents_->Focus();
}
void Shell::LoadDataWithBaseURL(const GURL& url, const std::string& data,
const GURL& base_url) {
const GURL data_url = GURL("data:text/html;charset=utf-8," + data);
NavigationController::LoadURLParams params(data_url);
params.load_type = NavigationController::LOAD_TYPE_DATA;
params.base_url_for_data_url = base_url;
params.virtual_url_for_data_url = url;
params.override_user_agent = NavigationController::UA_OVERRIDE_FALSE;
web_contents_->GetController().LoadURLWithParams(params);
web_contents_->Focus();
}
void Shell::AddNewContents(WebContents* source,
WebContents* new_contents,
WindowOpenDisposition disposition,
const gfx::Rect& initial_rect,
bool user_gesture,
bool* was_blocked) {
CreateShell(new_contents, AdjustWindowSize(initial_rect.size()));
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRunLayoutTest))
NotifyDoneForwarder::CreateForWebContents(new_contents);
}
void Shell::GoBackOrForward(int offset) {
web_contents_->GetController().GoToOffset(offset);
web_contents_->Focus();
}
void Shell::Reload() {
web_contents_->GetController().Reload(false);
web_contents_->Focus();
}
void Shell::Stop() {
web_contents_->Stop();
web_contents_->Focus();
}
void Shell::UpdateNavigationControls(bool to_different_document) {
int current_index = web_contents_->GetController().GetCurrentEntryIndex();
int max_index = web_contents_->GetController().GetEntryCount() - 1;
PlatformEnableUIControl(BACK_BUTTON, current_index > 0);
PlatformEnableUIControl(FORWARD_BUTTON, current_index < max_index);
PlatformEnableUIControl(STOP_BUTTON,
to_different_document && web_contents_->IsLoading());
}
void Shell::ShowDevTools() {
InnerShowDevTools();
}
void Shell::ShowDevToolsForElementAt(int x, int y) {
InnerShowDevTools();
devtools_frontend_->InspectElementAt(x, y);
}
void Shell::CloseDevTools() {
if (!devtools_frontend_)
return;
devtools_observer_.reset();
devtools_frontend_->Close();
devtools_frontend_ = NULL;
}
gfx::NativeView Shell::GetContentView() {
if (!web_contents_)
return NULL;
return web_contents_->GetNativeView();
}
void Shell::LoadingStateChanged(WebContents* source,
bool to_different_document) {
UpdateNavigationControls(to_different_document);
PlatformSetIsLoading(source->IsLoading());
}
void Shell::EnterFullscreenModeForTab(WebContents* web_contents,
const GURL& origin) {
ToggleFullscreenModeForTab(web_contents, true);
}
void Shell::ExitFullscreenModeForTab(WebContents* web_contents) {
ToggleFullscreenModeForTab(web_contents, false);
}
void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
bool enter_fullscreen) {
#if defined(OS_ANDROID)
PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen);
#endif
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRunLayoutTest))
return;
if (is_fullscreen_ != enter_fullscreen) {
is_fullscreen_ = enter_fullscreen;
web_contents->GetRenderViewHost()->GetWidget()->WasResized();
}
}
bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const {
#if defined(OS_ANDROID)
return PlatformIsFullscreenForTabOrPending(web_contents);
#else
return is_fullscreen_;
#endif
}
blink::WebDisplayMode Shell::GetDisplayMode(
const WebContents* web_contents) const {
// TODO : should return blink::WebDisplayModeFullscreen wherever user puts
// a browser window into fullscreen (not only in case of renderer-initiated
// fullscreen mode): crbug.com/476874.
return IsFullscreenForTabOrPending(web_contents) ?
blink::WebDisplayModeFullscreen : blink::WebDisplayModeBrowser;
}
void Shell::RequestToLockMouse(WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) {
web_contents->GotResponseToLockMouseRequest(true);
}
void Shell::CloseContents(WebContents* source) {
Close();
}
bool Shell::CanOverscrollContent() const {
#if defined(USE_AURA)
return true;
#else
return false;
#endif
}
void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
PlatformSetAddressBarURL(web_contents->GetLastCommittedURL());
}
JavaScriptDialogManager* Shell::GetJavaScriptDialogManager(
WebContents* source) {
if (!dialog_manager_) {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
dialog_manager_.reset(command_line.HasSwitch(switches::kRunLayoutTest)
? new LayoutTestJavaScriptDialogManager
: new ShellJavaScriptDialogManager);
}
return dialog_manager_.get();
}
scoped_ptr<BluetoothChooser> Shell::RunBluetoothChooser(
WebContents* web_contents,
const BluetoothChooser::EventHandler& event_handler,
const GURL& origin) {
const base::CommandLine& command_line =
*base::CommandLine::ForCurrentProcess();
if (command_line.HasSwitch(switches::kRunLayoutTest)) {
return BlinkTestController::Get()->RunBluetoothChooser(
web_contents, event_handler, origin);
}
return nullptr;
}
bool Shell::AddMessageToConsole(WebContents* source,
int32 level,
const base::string16& message,
int32 line_no,
const base::string16& source_id) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRunLayoutTest);
}
void Shell::RendererUnresponsive(WebContents* source) {
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kRunLayoutTest))
return;
BlinkTestController::Get()->RendererUnresponsive();
}
void Shell::ActivateContents(WebContents* contents) {
contents->GetRenderViewHost()->GetWidget()->Focus();
}
bool Shell::HandleContextMenu(const content::ContextMenuParams& params) {
return PlatformHandleContextMenu(params);
}
gfx::Size Shell::GetShellDefaultSize() {
static gfx::Size default_shell_size;
if (!default_shell_size.IsEmpty())
return default_shell_size;
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
if (command_line->HasSwitch(switches::kContentShellHostWindowSize)) {
const std::string size_str = command_line->GetSwitchValueASCII(
switches::kContentShellHostWindowSize);
int width, height;
CHECK_EQ(2, sscanf(size_str.c_str(), "%dx%d", &width, &height));
default_shell_size = gfx::Size(width, height);
} else {
default_shell_size = gfx::Size(
kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
}
return default_shell_size;
}
void Shell::TitleWasSet(NavigationEntry* entry, bool explicit_set) {
if (entry)
PlatformSetTitle(entry->GetTitle());
}
void Shell::InnerShowDevTools() {
if (!devtools_frontend_) {
devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
devtools_observer_.reset(new DevToolsWebContentsObserver(
this, devtools_frontend_->frontend_shell()->web_contents()));
}
devtools_frontend_->Activate();
devtools_frontend_->Focus();
}
void Shell::OnDevToolsWebContentsDestroyed() {
devtools_observer_.reset();
devtools_frontend_ = NULL;
}
} // namespace content