summaryrefslogtreecommitdiffstats
path: root/content/shell/browser
diff options
context:
space:
mode:
authorjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-20 11:30:41 +0000
committerjochen@chromium.org <jochen@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-08-20 11:30:41 +0000
commitde7d61ff0d16a335b4c5199bc638205df91700a5 (patch)
treebcd14deb2b6b242e2fc5e20bc136f177c2aa7c18 /content/shell/browser
parent8162d4474a101a16cc729c94e979cb3216e2aa9d (diff)
downloadchromium_src-de7d61ff0d16a335b4c5199bc638205df91700a5.zip
chromium_src-de7d61ff0d16a335b4c5199bc638205df91700a5.tar.gz
chromium_src-de7d61ff0d16a335b4c5199bc638205df91700a5.tar.bz2
[content shell] move browser process stuff into browser/ subdir
BUG=180021 R=marja@chromium.org TBR=joi@chromium.org,ben@chromium.org Review URL: https://chromiumcodereview.appspot.com/23316003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@218441 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'content/shell/browser')
-rw-r--r--content/shell/browser/minimal_shell.cc54
-rw-r--r--content/shell/browser/minimal_shell.h67
-rw-r--r--content/shell/browser/notify_done_forwarder.cc33
-rw-r--r--content/shell/browser/notify_done_forwarder.h34
-rw-r--r--content/shell/browser/shell.cc367
-rw-r--r--content/shell/browser/shell.h286
-rw-r--r--content/shell/browser/shell_android.cc93
-rw-r--r--content/shell/browser/shell_application_mac.h27
-rw-r--r--content/shell/browser/shell_application_mac.mm39
-rw-r--r--content/shell/browser/shell_aura.cc374
-rw-r--r--content/shell/browser/shell_browser_context.cc215
-rw-r--r--content/shell/browser/shell_browser_context.h83
-rw-r--r--content/shell/browser/shell_browser_main.cc220
-rw-r--r--content/shell/browser/shell_browser_main.h19
-rw-r--r--content/shell/browser/shell_browser_main_parts.cc175
-rw-r--r--content/shell/browser/shell_browser_main_parts.h70
-rw-r--r--content/shell/browser/shell_browser_main_parts_mac.mm25
-rw-r--r--content/shell/browser/shell_content_browser_client.cc275
-rw-r--r--content/shell/browser/shell_content_browser_client.h103
-rw-r--r--content/shell/browser/shell_devtools_delegate.cc119
-rw-r--r--content/shell/browser/shell_devtools_delegate.h50
-rw-r--r--content/shell/browser/shell_devtools_frontend.cc107
-rw-r--r--content/shell/browser/shell_devtools_frontend.h73
-rw-r--r--content/shell/browser/shell_download_manager_delegate.cc211
-rw-r--r--content/shell/browser/shell_download_manager_delegate.h65
-rw-r--r--content/shell/browser/shell_gtk.cc339
-rw-r--r--content/shell/browser/shell_javascript_dialog.h64
-rw-r--r--content/shell/browser/shell_javascript_dialog_gtk.cc127
-rw-r--r--content/shell/browser/shell_javascript_dialog_mac.mm138
-rw-r--r--content/shell/browser/shell_javascript_dialog_manager.cc143
-rw-r--r--content/shell/browser/shell_javascript_dialog_manager.h67
-rw-r--r--content/shell/browser/shell_javascript_dialog_win.cc113
-rw-r--r--content/shell/browser/shell_layout_tests_android.cc93
-rw-r--r--content/shell/browser/shell_layout_tests_android.h25
-rw-r--r--content/shell/browser/shell_login_dialog.cc107
-rw-r--r--content/shell/browser/shell_login_dialog.h97
-rw-r--r--content/shell/browser/shell_login_dialog_gtk.cc111
-rw-r--r--content/shell/browser/shell_login_dialog_mac.mm122
-rw-r--r--content/shell/browser/shell_mac.mm334
-rw-r--r--content/shell/browser/shell_message_filter.cc105
-rw-r--r--content/shell/browser/shell_message_filter.h66
-rw-r--r--content/shell/browser/shell_net_log.cc72
-rw-r--r--content/shell/browser/shell_net_log.h28
-rw-r--r--content/shell/browser/shell_network_delegate.cc127
-rw-r--r--content/shell/browser/shell_network_delegate.h71
-rw-r--r--content/shell/browser/shell_plugin_service_filter.cc31
-rw-r--r--content/shell/browser/shell_plugin_service_filter.h37
-rw-r--r--content/shell/browser/shell_quota_permission_context.cc32
-rw-r--r--content/shell/browser/shell_quota_permission_context.h34
-rw-r--r--content/shell/browser/shell_resource_dispatcher_host_delegate.cc44
-rw-r--r--content/shell/browser/shell_resource_dispatcher_host_delegate.h40
-rw-r--r--content/shell/browser/shell_url_request_context_getter.cc231
-rw-r--r--content/shell/browser/shell_url_request_context_getter.h69
-rw-r--r--content/shell/browser/shell_web_contents_view_delegate.h83
-rw-r--r--content/shell/browser/shell_web_contents_view_delegate_android.cc46
-rw-r--r--content/shell/browser/shell_web_contents_view_delegate_creator.h18
-rw-r--r--content/shell/browser/shell_web_contents_view_delegate_gtk.cc241
-rw-r--r--content/shell/browser/shell_web_contents_view_delegate_mac.mm277
-rw-r--r--content/shell/browser/shell_web_contents_view_delegate_win.cc254
-rw-r--r--content/shell/browser/shell_win.cc285
-rw-r--r--content/shell/browser/webkit_test_controller.cc632
-rw-r--r--content/shell/browser/webkit_test_controller.h219
62 files changed, 8106 insertions, 0 deletions
diff --git a/content/shell/browser/minimal_shell.cc b/content/shell/browser/minimal_shell.cc
new file mode 100644
index 0000000..e7e88f8
--- /dev/null
+++ b/content/shell/browser/minimal_shell.cc
@@ -0,0 +1,54 @@
+// 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/minimal_shell.h"
+
+#include "ui/aura/client/default_capture_client.h"
+#include "ui/aura/focus_manager.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/test/test_activation_client.h"
+#include "ui/views/corewm/compound_event_filter.h"
+#include "ui/views/corewm/input_method_event_filter.h"
+
+namespace content {
+
+MinimalShell::MinimalShell(const gfx::Size& default_window_size) {
+ root_window_.reset(new aura::RootWindow(
+ aura::RootWindow::CreateParams(
+ gfx::Rect(default_window_size))));
+ root_window_->Init();
+ aura::client::SetStackingClient(root_window_.get(), this);
+
+ focus_client_.reset(new aura::FocusManager);
+ aura::client::SetFocusClient(root_window_.get(), focus_client_.get());
+
+ root_window_event_filter_ = new views::corewm::CompoundEventFilter;
+ // Pass ownership of the filter to the root_window.
+ root_window_->SetEventFilter(root_window_event_filter_);
+
+ input_method_filter_.reset(new views::corewm::InputMethodEventFilter(
+ root_window_->GetAcceleratedWidget()));
+ input_method_filter_->SetInputMethodPropertyInRootWindow(
+ root_window_.get());
+ root_window_event_filter_->AddHandler(input_method_filter_.get());
+
+ test_activation_client_.reset(
+ new aura::test::TestActivationClient(root_window_.get()));
+
+ capture_client_.reset(
+ new aura::client::DefaultCaptureClient(root_window_.get()));
+}
+
+MinimalShell::~MinimalShell() {
+ root_window_event_filter_->RemoveHandler(input_method_filter_.get());
+}
+
+aura::Window* MinimalShell::GetDefaultParent(
+ aura::Window* context,
+ aura::Window* window,
+ const gfx::Rect& bounds) {
+ return root_window_.get();
+}
+
+} // namespace content
diff --git a/content/shell/browser/minimal_shell.h b/content/shell/browser/minimal_shell.h
new file mode 100644
index 0000000..1388da9
--- /dev/null
+++ b/content/shell/browser/minimal_shell.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_MINIMAL_SHELL_H_
+#define CONTENT_SHELL_BROWSER_MINIMAL_SHELL_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/client/stacking_client.h"
+
+namespace aura {
+class RootWindow;
+class Window;
+namespace client {
+class DefaultCaptureClient;
+class FocusClient;
+}
+namespace test {
+class TestActivationClient;
+}
+}
+
+namespace gfx {
+class Rect;
+class Size;
+}
+
+namespace views {
+namespace corewm {
+class CompoundEventFilter;
+class InputMethodEventFilter;
+}
+}
+
+namespace content {
+
+// Creates a minimal environment for running the shell. We can't pull in all of
+// ash here, but we can create attach several of the same things we'd find in
+// the ash parts of the code.
+class MinimalShell : public aura::client::StackingClient {
+ public:
+ explicit MinimalShell(const gfx::Size& default_window_size);
+ virtual ~MinimalShell();
+
+ // Overridden from client::StackingClient:
+ virtual aura::Window* GetDefaultParent(aura::Window* context,
+ aura::Window* window,
+ const gfx::Rect& bounds) OVERRIDE;
+
+ private:
+ scoped_ptr<aura::RootWindow> root_window_;
+
+ // Owned by RootWindow
+ views::corewm::CompoundEventFilter* root_window_event_filter_;
+
+ scoped_ptr<aura::client::DefaultCaptureClient> capture_client_;
+ scoped_ptr<views::corewm::InputMethodEventFilter> input_method_filter_;
+ scoped_ptr<aura::test::TestActivationClient> test_activation_client_;
+ scoped_ptr<aura::client::FocusClient> focus_client_;
+
+ DISALLOW_COPY_AND_ASSIGN(MinimalShell);
+};
+
+} // namespace content;
+
+#endif // CONTENT_SHELL_BROWSER_MINIMAL_SHELL_H_
diff --git a/content/shell/browser/notify_done_forwarder.cc b/content/shell/browser/notify_done_forwarder.cc
new file mode 100644
index 0000000..6d8f104
--- /dev/null
+++ b/content/shell/browser/notify_done_forwarder.cc
@@ -0,0 +1,33 @@
+// 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/notify_done_forwarder.h"
+
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_messages.h"
+
+namespace content {
+
+DEFINE_WEB_CONTENTS_USER_DATA_KEY(NotifyDoneForwarder);
+
+NotifyDoneForwarder::NotifyDoneForwarder(WebContents* web_contents)
+ : WebContentsObserver(web_contents) {}
+
+NotifyDoneForwarder::~NotifyDoneForwarder() {}
+
+bool NotifyDoneForwarder::OnMessageReceived(const IPC::Message& message) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(NotifyDoneForwarder, message)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinishedInSecondaryWindow,
+ OnTestFinishedInSecondaryWindow)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+ return handled;
+}
+
+void NotifyDoneForwarder::OnTestFinishedInSecondaryWindow() {
+ WebKitTestController::Get()->TestFinishedInSecondaryWindow();
+}
+
+} // namespace content
diff --git a/content/shell/browser/notify_done_forwarder.h b/content/shell/browser/notify_done_forwarder.h
new file mode 100644
index 0000000..e5a2f3f7
--- /dev/null
+++ b/content/shell/browser/notify_done_forwarder.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_NOTIFY_DONE_FORWARDER_H_
+#define CONTENT_SHELL_BROWSER_NOTIFY_DONE_FORWARDER_H_
+
+#include "base/basictypes.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_user_data.h"
+
+namespace content {
+
+class NotifyDoneForwarder : public WebContentsObserver,
+ public WebContentsUserData<NotifyDoneForwarder> {
+ public:
+ virtual ~NotifyDoneForwarder();
+
+ // WebContentsObserver implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+
+ private:
+ friend class WebContentsUserData<NotifyDoneForwarder>;
+
+ explicit NotifyDoneForwarder(WebContents* web_contents);
+
+ void OnTestFinishedInSecondaryWindow();
+
+ DISALLOW_COPY_AND_ASSIGN(NotifyDoneForwarder);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_NOTIFY_DONE_FORWARDER_H_
diff --git a/content/shell/browser/shell.cc b/content/shell/browser/shell.cc
new file mode 100644
index 0000000..c8616d3
--- /dev/null
+++ b/content/shell/browser/shell.cc
@@ -0,0 +1,367 @@
+// 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/message_loop/message_loop.h"
+#include "base/path_service.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 "content/public/browser/devtools_manager.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/notification_details.h"
+#include "content/public/browser/notification_source.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/renderer_preferences.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/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_messages.h"
+#include "content/shell/common/shell_switches.h"
+
+namespace content {
+
+const int Shell::kDefaultTestWindowWidthDip = 800;
+const int Shell::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
+ virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE {
+ shell_->OnDevToolsWebContentsDestroyed();
+ }
+
+ private:
+ Shell* shell_;
+
+ DISALLOW_COPY_AND_ASSIGN(DevToolsWebContentsObserver);
+};
+
+Shell::Shell(WebContents* web_contents)
+ : devtools_frontend_(NULL),
+ is_fullscreen_(false),
+ window_(NULL),
+ url_edit_view_(NULL),
+#if defined(OS_WIN) && !defined(USE_AURA)
+ default_edit_wnd_proc_(0),
+#endif
+ headless_(false) {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (command_line.HasSwitch(switches::kDumpRenderTree))
+ headless_ = true;
+ registrar_.Add(this, NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED,
+ Source<WebContents>(web_contents));
+ 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_)
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::MessageLoop::QuitClosure());
+}
+
+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();
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+ web_contents->GetMutableRendererPrefs()->use_custom_colors = false;
+ web_contents->GetRenderViewHost()->SyncRendererPrefs();
+ }
+
+ return shell;
+}
+
+void Shell::CloseAllWindows() {
+ base::AutoReset<bool> auto_reset(&quit_message_loop_, false);
+ DevToolsManager::GetInstance()->CloseAllClientHosts();
+ std::vector<Shell*> open_windows(windows_);
+ for (size_t i = 0; i < open_windows.size(); ++i)
+ open_windows[i]->Close();
+ base::MessageLoop::current()->RunUntilIdle();
+}
+
+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(
+ gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip));
+}
+
+Shell* Shell::CreateNewWindow(BrowserContext* browser_context,
+ const GURL& url,
+ SiteInstance* site_instance,
+ int routing_id,
+ const gfx::Size& initial_size) {
+ WebContents::CreateParams create_params(browser_context, site_instance);
+ create_params.routing_id = routing_id;
+ if (!initial_size.IsEmpty())
+ create_params.initial_size = initial_size;
+ else
+ create_params.initial_size =
+ gfx::Size(kDefaultTestWindowWidthDip, kDefaultTestWindowHeightDip);
+ 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 = PageTransitionFromInt(
+ PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR);
+ params.frame_name = frame_name;
+ web_contents_->GetController().LoadURLWithParams(params);
+ web_contents_->GetView()->Focus();
+}
+
+void Shell::GoBackOrForward(int offset) {
+ web_contents_->GetController().GoToOffset(offset);
+ web_contents_->GetView()->Focus();
+}
+
+void Shell::Reload() {
+ web_contents_->GetController().Reload(false);
+ web_contents_->GetView()->Focus();
+}
+
+void Shell::Stop() {
+ web_contents_->Stop();
+ web_contents_->GetView()->Focus();
+}
+
+void Shell::UpdateNavigationControls() {
+ 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, web_contents_->IsLoading());
+}
+
+void Shell::ShowDevTools() {
+ if (devtools_frontend_) {
+ devtools_frontend_->Focus();
+ return;
+ }
+ devtools_frontend_ = ShellDevToolsFrontend::Show(web_contents());
+ devtools_observer_.reset(new DevToolsWebContentsObserver(
+ this, devtools_frontend_->frontend_shell()->web_contents()));
+}
+
+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_->GetView()->GetNativeView();
+}
+
+WebContents* Shell::OpenURLFromTab(WebContents* source,
+ const OpenURLParams& params) {
+ // The only one we implement for now.
+ DCHECK(params.disposition == CURRENT_TAB);
+ NavigationController::LoadURLParams load_url_params(params.url);
+ load_url_params.referrer = params.referrer;
+ load_url_params.transition_type = params.transition;
+ load_url_params.extra_headers = params.extra_headers;
+ load_url_params.should_replace_current_entry =
+ params.should_replace_current_entry;
+
+ if (params.transferred_global_request_id != GlobalRequestID()) {
+ load_url_params.is_renderer_initiated = params.is_renderer_initiated;
+ load_url_params.transferred_global_request_id =
+ params.transferred_global_request_id;
+ } else if (params.is_renderer_initiated) {
+ load_url_params.is_renderer_initiated = true;
+ }
+
+ source->GetController().LoadURLWithParams(load_url_params);
+ return source;
+}
+
+void Shell::LoadingStateChanged(WebContents* source) {
+ UpdateNavigationControls();
+ PlatformSetIsLoading(source->IsLoading());
+}
+
+void Shell::ToggleFullscreenModeForTab(WebContents* web_contents,
+ bool enter_fullscreen) {
+#if defined(OS_ANDROID)
+ PlatformToggleFullscreenModeForTab(web_contents, enter_fullscreen);
+#endif
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+ if (is_fullscreen_ != enter_fullscreen) {
+ is_fullscreen_ = enter_fullscreen;
+ web_contents->GetRenderViewHost()->WasResized();
+ }
+}
+
+bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const {
+#if defined(OS_ANDROID)
+ return PlatformIsFullscreenForTabOrPending(web_contents);
+#else
+ return is_fullscreen_;
+#endif
+}
+
+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::WebContentsCreated(WebContents* source_contents,
+ int64 source_frame_id,
+ const string16& frame_name,
+ const GURL& target_url,
+ WebContents* new_contents) {
+ CreateShell(new_contents, source_contents->GetView()->GetContainerSize());
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ NotifyDoneForwarder::CreateForWebContents(new_contents);
+}
+
+void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) {
+ PlatformSetAddressBarURL(web_contents->GetLastCommittedURL());
+}
+
+JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() {
+ if (!dialog_manager_)
+ dialog_manager_.reset(new ShellJavaScriptDialogManager());
+ return dialog_manager_.get();
+}
+
+bool Shell::AddMessageToConsole(WebContents* source,
+ int32 level,
+ const string16& message,
+ int32 line_no,
+ const string16& source_id) {
+ return CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
+}
+
+void Shell::RendererUnresponsive(WebContents* source) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+ WebKitTestController::Get()->RendererUnresponsive();
+}
+
+void Shell::ActivateContents(WebContents* contents) {
+ contents->GetRenderViewHost()->Focus();
+}
+
+void Shell::DeactivateContents(WebContents* contents) {
+ contents->GetRenderViewHost()->Blur();
+}
+
+void Shell::WorkerCrashed(WebContents* source) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+ WebKitTestController::Get()->WorkerCrashed();
+}
+
+void Shell::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type == NOTIFICATION_WEB_CONTENTS_TITLE_UPDATED) {
+ std::pair<NavigationEntry*, bool>* title =
+ Details<std::pair<NavigationEntry*, bool> >(details).ptr();
+
+ if (title->first) {
+ string16 text = title->first->GetTitle();
+ PlatformSetTitle(text);
+ }
+ } else {
+ NOTREACHED();
+ }
+}
+
+void Shell::OnDevToolsWebContentsDestroyed() {
+ devtools_observer_.reset();
+ devtools_frontend_ = NULL;
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
new file mode 100644
index 0000000..24c58c8
--- /dev/null
+++ b/content/shell/browser/shell.h
@@ -0,0 +1,286 @@
+// 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.
+#ifndef CONTENT_SHELL_BROWSER_SHELL_H_
+#define CONTENT_SHELL_BROWSER_SHELL_H_
+
+
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/callback_forward.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/string_piece.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "ipc/ipc_channel.h"
+#include "ui/gfx/native_widget_types.h"
+#include "ui/gfx/size.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#include "ui/base/gtk/gtk_signal.h"
+
+typedef struct _GtkToolItem GtkToolItem;
+#elif defined(OS_ANDROID)
+#include "base/android/scoped_java_ref.h"
+#elif defined(USE_AURA)
+#if defined(OS_CHROMEOS)
+namespace content {
+class MinimalShell;
+}
+#endif
+namespace views {
+class Widget;
+class ViewsDelegate;
+}
+#endif
+
+class GURL;
+namespace content {
+
+class BrowserContext;
+class ShellDevToolsFrontend;
+class ShellJavaScriptDialogManager;
+class SiteInstance;
+class WebContents;
+
+// This represents one window of the Content Shell, i.e. all the UI including
+// buttons and url bar, as well as the web content area.
+class Shell : public WebContentsDelegate,
+ public NotificationObserver {
+ public:
+ static const int kDefaultTestWindowWidthDip;
+ static const int kDefaultTestWindowHeightDip;
+
+ virtual ~Shell();
+
+ void LoadURL(const GURL& url);
+ void LoadURLForFrame(const GURL& url, const std::string& frame_name);
+ void GoBackOrForward(int offset);
+ void Reload();
+ void Stop();
+ void UpdateNavigationControls();
+ void Close();
+ void ShowDevTools();
+ void CloseDevTools();
+#if (defined(OS_WIN) && !defined(USE_AURA)) || \
+ defined(TOOLKIT_GTK) || defined(OS_MACOSX)
+ // Resizes the main window to the given dimensions.
+ void SizeTo(int width, int height);
+#endif
+
+ // Do one time initialization at application startup.
+ static void Initialize();
+
+ static Shell* CreateNewWindow(BrowserContext* browser_context,
+ const GURL& url,
+ SiteInstance* site_instance,
+ int routing_id,
+ const gfx::Size& initial_size);
+
+ // Returns the Shell object corresponding to the given RenderViewHost.
+ static Shell* FromRenderViewHost(RenderViewHost* rvh);
+
+ // Returns the currently open windows.
+ static std::vector<Shell*>& windows() { return windows_; }
+
+ // Closes all windows and returns. This runs a message loop.
+ static void CloseAllWindows();
+
+ // Closes all windows and exits.
+ static void PlatformExit();
+
+ // Used for content_browsertests. Called once.
+ static void SetShellCreatedCallback(
+ base::Callback<void(Shell*)> shell_created_callback);
+
+ WebContents* web_contents() const { return web_contents_.get(); }
+ gfx::NativeWindow window() { return window_; }
+
+#if defined(OS_MACOSX)
+ // Public to be called by an ObjC bridge object.
+ void ActionPerformed(int control);
+ void URLEntered(std::string url_string);
+#elif defined(OS_ANDROID)
+ // Registers the Android Java to native methods.
+ static bool Register(JNIEnv* env);
+#endif
+
+ // WebContentsDelegate
+ virtual WebContents* OpenURLFromTab(WebContents* source,
+ const OpenURLParams& params) OVERRIDE;
+ virtual void LoadingStateChanged(WebContents* source) OVERRIDE;
+#if defined(OS_ANDROID)
+ virtual void LoadProgressChanged(WebContents* source,
+ double progress) OVERRIDE;
+#endif
+ virtual void ToggleFullscreenModeForTab(WebContents* web_contents,
+ bool enter_fullscreen) OVERRIDE;
+ virtual bool IsFullscreenForTabOrPending(
+ const WebContents* web_contents) const OVERRIDE;
+ virtual void RequestToLockMouse(WebContents* web_contents,
+ bool user_gesture,
+ bool last_unlocked_by_target) OVERRIDE;
+ virtual void CloseContents(WebContents* source) OVERRIDE;
+ virtual bool CanOverscrollContent() const OVERRIDE;
+ virtual void WebContentsCreated(WebContents* source_contents,
+ int64 source_frame_id,
+ const string16& frame_name,
+ const GURL& target_url,
+ WebContents* new_contents) OVERRIDE;
+ virtual void DidNavigateMainFramePostCommit(
+ WebContents* web_contents) OVERRIDE;
+ virtual JavaScriptDialogManager* GetJavaScriptDialogManager() OVERRIDE;
+#if defined(OS_MACOSX)
+ virtual void HandleKeyboardEvent(
+ WebContents* source,
+ const NativeWebKeyboardEvent& event) OVERRIDE;
+#endif
+ virtual bool AddMessageToConsole(WebContents* source,
+ int32 level,
+ const string16& message,
+ int32 line_no,
+ const string16& source_id) OVERRIDE;
+ virtual void RendererUnresponsive(WebContents* source) OVERRIDE;
+ virtual void ActivateContents(WebContents* contents) OVERRIDE;
+ virtual void DeactivateContents(WebContents* contents) OVERRIDE;
+ virtual void WorkerCrashed(WebContents* source) OVERRIDE;
+
+ private:
+ enum UIControl {
+ BACK_BUTTON,
+ FORWARD_BUTTON,
+ STOP_BUTTON
+ };
+
+ class DevToolsWebContentsObserver;
+
+ explicit Shell(WebContents* web_contents);
+
+ // Helper to create a new Shell given a newly created WebContents.
+ static Shell* CreateShell(WebContents* web_contents,
+ const gfx::Size& initial_size);
+
+ // Helper for one time initialization of application
+ static void PlatformInitialize(const gfx::Size& default_window_size);
+
+ // All the methods that begin with Platform need to be implemented by the
+ // platform specific Shell implementation.
+ // Called from the destructor to let each platform do any necessary cleanup.
+ void PlatformCleanUp();
+ // Creates the main window GUI.
+ void PlatformCreateWindow(int width, int height);
+ // Links the WebContents into the newly created window.
+ void PlatformSetContents();
+ // Resize the content area and GUI.
+ void PlatformResizeSubViews();
+ // Enable/disable a button.
+ void PlatformEnableUIControl(UIControl control, bool is_enabled);
+ // Updates the url in the url bar.
+ void PlatformSetAddressBarURL(const GURL& url);
+ // Sets whether the spinner is spinning.
+ void PlatformSetIsLoading(bool loading);
+ // Set the title of shell window
+ void PlatformSetTitle(const string16& title);
+#if defined(OS_ANDROID)
+ void PlatformToggleFullscreenModeForTab(WebContents* web_contents,
+ bool enter_fullscreen);
+ bool PlatformIsFullscreenForTabOrPending(
+ const WebContents* web_contents) const;
+#endif
+
+ gfx::NativeView GetContentView();
+
+ // NotificationObserver
+ virtual void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) OVERRIDE;
+
+ void OnDevToolsWebContentsDestroyed();
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+ static ATOM RegisterWindowClass();
+ static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+ static LRESULT CALLBACK EditWndProc(HWND, UINT, WPARAM, LPARAM);
+#elif defined(TOOLKIT_GTK)
+ CHROMEGTK_CALLBACK_0(Shell, void, OnBackButtonClicked);
+ CHROMEGTK_CALLBACK_0(Shell, void, OnForwardButtonClicked);
+ CHROMEGTK_CALLBACK_0(Shell, void, OnReloadButtonClicked);
+ CHROMEGTK_CALLBACK_0(Shell, void, OnStopButtonClicked);
+ CHROMEGTK_CALLBACK_0(Shell, void, OnURLEntryActivate);
+ CHROMEGTK_CALLBACK_0(Shell, gboolean, OnWindowDestroyed);
+
+ CHROMEG_CALLBACK_3(Shell, gboolean, OnCloseWindowKeyPressed, GtkAccelGroup*,
+ GObject*, guint, GdkModifierType);
+ CHROMEG_CALLBACK_3(Shell, gboolean, OnNewWindowKeyPressed, GtkAccelGroup*,
+ GObject*, guint, GdkModifierType);
+ CHROMEG_CALLBACK_3(Shell, gboolean, OnHighlightURLView, GtkAccelGroup*,
+ GObject*, guint, GdkModifierType);
+ CHROMEG_CALLBACK_3(Shell, gboolean, OnReloadKeyPressed, GtkAccelGroup*,
+ GObject*, guint, GdkModifierType);
+#endif
+
+ scoped_ptr<ShellJavaScriptDialogManager> dialog_manager_;
+
+ scoped_ptr<WebContents> web_contents_;
+
+ scoped_ptr<DevToolsWebContentsObserver> devtools_observer_;
+ ShellDevToolsFrontend* devtools_frontend_;
+
+ bool is_fullscreen_;
+
+ gfx::NativeWindow window_;
+ gfx::NativeEditView url_edit_view_;
+
+ // Notification manager
+ NotificationRegistrar registrar_;
+
+#if defined(OS_WIN) && !defined(USE_AURA)
+ WNDPROC default_edit_wnd_proc_;
+ static HINSTANCE instance_handle_;
+#elif defined(TOOLKIT_GTK)
+ GtkWidget* vbox_;
+
+ GtkToolItem* back_button_;
+ GtkToolItem* forward_button_;
+ GtkToolItem* reload_button_;
+ GtkToolItem* stop_button_;
+
+ GtkWidget* spinner_;
+ GtkToolItem* spinner_item_;
+
+ int content_width_;
+ int content_height_;
+ int ui_elements_height_; // height of menubar, toolbar, etc.
+#elif defined(OS_ANDROID)
+ base::android::ScopedJavaGlobalRef<jobject> java_object_;
+#elif defined(USE_AURA)
+#if defined(OS_CHROMEOS)
+ static content::MinimalShell* minimal_shell_;
+#endif
+ static views::ViewsDelegate* views_delegate_;
+
+ views::Widget* window_widget_;
+#elif defined(OS_MACOSX)
+ int content_width_;
+ int content_height_;
+#endif
+
+ bool headless_;
+
+ // A container of all the open windows. We use a vector so we can keep track
+ // of ordering.
+ static std::vector<Shell*> windows_;
+
+ static base::Callback<void(Shell*)> shell_created_callback_;
+
+ // True if the destructur of Shell should post a quit closure on the current
+ // message loop if the destructed Shell object was the last one.
+ static bool quit_message_loop_;
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_H_
diff --git a/content/shell/browser/shell_android.cc b/content/shell/browser/shell_android.cc
new file mode 100644
index 0000000..d827e96
--- /dev/null
+++ b/content/shell/browser/shell_android.cc
@@ -0,0 +1,93 @@
+// 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 <jni.h>
+
+#include "base/android/jni_string.h"
+#include "base/android/scoped_java_ref.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "content/public/common/content_switches.h"
+#include "content/shell/android/shell_manager.h"
+#include "jni/Shell_jni.h"
+
+using base::android::AttachCurrentThread;
+using base::android::ConvertUTF8ToJavaString;
+
+namespace content {
+
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ DCHECK(command_line->HasSwitch(switches::kForceCompositingMode));
+ DCHECK(command_line->HasSwitch(switches::kEnableThreadedCompositing));
+}
+
+void Shell::PlatformCleanUp() {
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+ JNIEnv* env = AttachCurrentThread();
+ ScopedJavaLocalRef<jstring> j_url = ConvertUTF8ToJavaString(env, url.spec());
+ Java_Shell_onUpdateUrl(env, java_object_.obj(), j_url.obj());
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_Shell_setIsLoading(env, java_object_.obj(), loading);
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+ java_object_.Reset(AttachCurrentThread(), CreateShellView(this));
+}
+
+void Shell::PlatformSetContents() {
+ JNIEnv* env = AttachCurrentThread();
+ Java_Shell_initFromNativeTabContents(
+ env, java_object_.obj(), reinterpret_cast<jint>(web_contents()));
+}
+
+void Shell::PlatformResizeSubViews() {
+ // Not needed; subviews are bound.
+}
+
+void Shell::PlatformSetTitle(const string16& title) {
+ NOTIMPLEMENTED();
+}
+
+void Shell::LoadProgressChanged(WebContents* source, double progress) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_Shell_onLoadProgressChanged(env, java_object_.obj(), progress);
+}
+
+void Shell::PlatformToggleFullscreenModeForTab(WebContents* web_contents,
+ bool enter_fullscreen) {
+ JNIEnv* env = AttachCurrentThread();
+ Java_Shell_toggleFullscreenModeForTab(
+ env, java_object_.obj(), enter_fullscreen);
+}
+
+bool Shell::PlatformIsFullscreenForTabOrPending(
+ const WebContents* web_contents) const {
+ JNIEnv* env = AttachCurrentThread();
+ return Java_Shell_isFullscreenForTabOrPending(env, java_object_.obj());
+}
+
+void Shell::Close() {
+ CloseShellView(java_object_.obj());
+ java_object_.Reset();
+ delete this;
+}
+
+// static
+bool Shell::Register(JNIEnv* env) {
+ return RegisterNativesImpl(env);
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_application_mac.h b/content/shell/browser/shell_application_mac.h
new file mode 100644
index 0000000..bcba5a5
--- /dev/null
+++ b/content/shell/browser/shell_application_mac.h
@@ -0,0 +1,27 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_APPLICATION_MAC_H_
+#define CONTENT_SHELL_BROWSER_SHELL_APPLICATION_MAC_H_
+
+#include "base/mac/scoped_sending_event.h"
+#include "base/message_loop/message_pump_mac.h"
+
+@interface ShellCrApplication : NSApplication<CrAppProtocol,
+ CrAppControlProtocol> {
+ @private
+ BOOL handlingSendEvent_;
+}
+
+// CrAppProtocol:
+- (BOOL)isHandlingSendEvent;
+
+// CrAppControlProtocol:
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent;
+
+- (IBAction)newDocument:(id)sender;
+
+@end
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_APPLICATION_MAC_H_
diff --git a/content/shell/browser/shell_application_mac.mm b/content/shell/browser/shell_application_mac.mm
new file mode 100644
index 0000000..e18df5b
--- /dev/null
+++ b/content/shell/browser/shell_application_mac.mm
@@ -0,0 +1,39 @@
+// 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_application_mac.h"
+
+#include "base/auto_reset.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "url/gurl.h"
+
+@implementation ShellCrApplication
+
+- (BOOL)isHandlingSendEvent {
+ return handlingSendEvent_;
+}
+
+- (void)sendEvent:(NSEvent*)event {
+ base::AutoReset<BOOL> scoper(&handlingSendEvent_, YES);
+ [super sendEvent:event];
+}
+
+- (void)setHandlingSendEvent:(BOOL)handlingSendEvent {
+ handlingSendEvent_ = handlingSendEvent;
+}
+
+- (IBAction)newDocument:(id)sender {
+ content::ShellBrowserContext* browserContext =
+ content::ShellContentBrowserClient::Get()->browser_context();
+ content::Shell::CreateNewWindow(browserContext,
+ GURL(content::kAboutBlankURL),
+ NULL,
+ MSG_ROUTING_NONE,
+ gfx::Size());
+}
+
+@end
diff --git a/content/shell/browser/shell_aura.cc b/content/shell/browser/shell_aura.cc
new file mode 100644
index 0000000..03884da
--- /dev/null
+++ b/content/shell/browser/shell_aura.cc
@@ -0,0 +1,374 @@
+// 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/command_line.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "ui/aura/env.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window.h"
+#include "ui/base/accessibility/accessibility_types.h"
+#include "ui/base/clipboard/clipboard.h"
+#include "ui/base/events/event.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "ui/gfx/screen.h"
+#include "ui/views/controls/button/label_button.h"
+#include "ui/views/controls/textfield/textfield.h"
+#include "ui/views/controls/textfield/textfield_controller.h"
+#include "ui/views/controls/webview/webview.h"
+#include "ui/views/layout/fill_layout.h"
+#include "ui/views/layout/grid_layout.h"
+#include "ui/views/test/desktop_test_views_delegate.h"
+#include "ui/views/view.h"
+#include "ui/views/widget/desktop_aura/desktop_screen.h"
+#include "ui/views/widget/widget.h"
+#include "ui/views/widget/widget_delegate.h"
+
+#if defined(OS_CHROMEOS)
+#include "chromeos/dbus/dbus_thread_manager.h"
+#include "content/shell/browser/minimal_shell.h"
+#include "ui/aura/test/test_screen.h"
+#endif
+
+namespace content {
+
+namespace {
+// ViewDelegate implementation for aura content shell
+class ShellViewsDelegateAura : public views::DesktopTestViewsDelegate {
+ public:
+ ShellViewsDelegateAura() : use_transparent_windows_(false) {
+ }
+
+ virtual ~ShellViewsDelegateAura() {
+ }
+
+ void SetUseTransparentWindows(bool transparent) {
+ use_transparent_windows_ = transparent;
+ }
+
+ // Overridden from views::TestViewsDelegate:
+ virtual bool UseTransparentWindows() const OVERRIDE {
+ return use_transparent_windows_;
+ }
+
+ private:
+ bool use_transparent_windows_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellViewsDelegateAura);
+};
+
+// Maintain the UI controls and web view for content shell
+class ShellWindowDelegateView : public views::WidgetDelegateView,
+ public views::TextfieldController,
+ public views::ButtonListener {
+ public:
+ enum UIControl {
+ BACK_BUTTON,
+ FORWARD_BUTTON,
+ STOP_BUTTON
+ };
+
+ ShellWindowDelegateView(Shell* shell)
+ : shell_(shell),
+ toolbar_view_(new View),
+ contents_view_(new View) {
+ }
+ virtual ~ShellWindowDelegateView() {}
+
+ // Update the state of UI controls
+ void SetAddressBarURL(const GURL& url) {
+ url_entry_->SetText(ASCIIToUTF16(url.spec()));
+ }
+ void SetWebContents(WebContents* web_contents) {
+ contents_view_->SetLayoutManager(new views::FillLayout());
+ web_view_ = new views::WebView(web_contents->GetBrowserContext());
+ web_view_->SetWebContents(web_contents);
+ web_contents->GetView()->Focus();
+ contents_view_->AddChildView(web_view_);
+ Layout();
+ }
+ void SetWindowTitle(const string16& title) { title_ = title; }
+ void EnableUIControl(UIControl control, bool is_enabled) {
+ if (control == BACK_BUTTON) {
+ back_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
+ : views::CustomButton::STATE_DISABLED);
+ } else if (control == FORWARD_BUTTON) {
+ forward_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
+ : views::CustomButton::STATE_DISABLED);
+ } else if (control == STOP_BUTTON) {
+ stop_button_->SetState(is_enabled ? views::CustomButton::STATE_NORMAL
+ : views::CustomButton::STATE_DISABLED);
+ }
+ }
+
+ private:
+ // Initialize the UI control contained in shell window
+ void InitShellWindow() {
+ set_background(views::Background::CreateStandardPanelBackground());
+
+ views::GridLayout* layout = new views::GridLayout(this);
+ SetLayoutManager(layout);
+
+ views::ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddPaddingColumn(0, 2);
+ column_set->AddColumn(views::GridLayout::FILL, views::GridLayout::FILL, 1,
+ views::GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, 2);
+
+ layout->AddPaddingRow(0, 2);
+
+ // Add toolbar buttons and URL text field
+ {
+ layout->StartRow(0, 0);
+ views::GridLayout* toolbar_layout = new views::GridLayout(toolbar_view_);
+ toolbar_view_->SetLayoutManager(toolbar_layout);
+
+ views::ColumnSet* toolbar_column_set =
+ toolbar_layout->AddColumnSet(0);
+ // Back button
+ back_button_ = new views::LabelButton(this, ASCIIToUTF16("Back"));
+ back_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+ gfx::Size back_button_size = back_button_->GetPreferredSize();
+ toolbar_column_set->AddColumn(views::GridLayout::CENTER,
+ views::GridLayout::CENTER, 0,
+ views::GridLayout::FIXED,
+ back_button_size.width(),
+ back_button_size.width() / 2);
+ // Forward button
+ forward_button_ = new views::LabelButton(this, ASCIIToUTF16("Forward"));
+ forward_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+ gfx::Size forward_button_size = forward_button_->GetPreferredSize();
+ toolbar_column_set->AddColumn(views::GridLayout::CENTER,
+ views::GridLayout::CENTER, 0,
+ views::GridLayout::FIXED,
+ forward_button_size.width(),
+ forward_button_size.width() / 2);
+ // Refresh button
+ refresh_button_ = new views::LabelButton(this, ASCIIToUTF16("Refresh"));
+ refresh_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+ gfx::Size refresh_button_size = refresh_button_->GetPreferredSize();
+ toolbar_column_set->AddColumn(views::GridLayout::CENTER,
+ views::GridLayout::CENTER, 0,
+ views::GridLayout::FIXED,
+ refresh_button_size.width(),
+ refresh_button_size.width() / 2);
+ // Stop button
+ stop_button_ = new views::LabelButton(this, ASCIIToUTF16("Stop"));
+ stop_button_->SetStyle(views::Button::STYLE_NATIVE_TEXTBUTTON);
+ gfx::Size stop_button_size = stop_button_->GetPreferredSize();
+ toolbar_column_set->AddColumn(views::GridLayout::CENTER,
+ views::GridLayout::CENTER, 0,
+ views::GridLayout::FIXED,
+ stop_button_size.width(),
+ stop_button_size.width() / 2);
+ toolbar_column_set->AddPaddingColumn(0, 2);
+ // URL entry
+ url_entry_ = new views::Textfield();
+ url_entry_->SetController(this);
+ toolbar_column_set->AddColumn(views::GridLayout::FILL,
+ views::GridLayout::FILL, 1,
+ views::GridLayout::USE_PREF, 0, 0);
+
+ // Fill up the first row
+ toolbar_layout->StartRow(0, 0);
+ toolbar_layout->AddView(back_button_);
+ toolbar_layout->AddView(forward_button_);
+ toolbar_layout->AddView(refresh_button_);
+ toolbar_layout->AddView(stop_button_);
+ toolbar_layout->AddView(url_entry_);
+
+ layout->AddView(toolbar_view_);
+ }
+
+ layout->AddPaddingRow(0, 5);
+
+ // Add web contents view as the second row
+ {
+ layout->StartRow(1, 0);
+ layout->AddView(contents_view_);
+ }
+
+ layout->AddPaddingRow(0, 5);
+ }
+ // Overridden from TextfieldController
+ virtual void ContentsChanged(views::Textfield* sender,
+ const string16& new_contents) OVERRIDE {
+ }
+ virtual bool HandleKeyEvent(views::Textfield* sender,
+ const ui::KeyEvent& key_event) OVERRIDE {
+ if (sender == url_entry_ && key_event.key_code() == ui::VKEY_RETURN) {
+ std::string text = UTF16ToUTF8(url_entry_->text());
+ GURL url(text);
+ if (!url.has_scheme()) {
+ url = GURL(std::string("http://") + std::string(text));
+ url_entry_->SetText(ASCIIToUTF16(url.spec()));
+ }
+ shell_->LoadURL(url);
+ return true;
+ }
+ return false;
+ }
+
+ // Overridden from ButtonListener
+ virtual void ButtonPressed(views::Button* sender,
+ const ui::Event& event) OVERRIDE {
+ if (sender == back_button_)
+ shell_->GoBackOrForward(-1);
+ else if (sender == forward_button_)
+ shell_->GoBackOrForward(1);
+ else if (sender == refresh_button_)
+ shell_->Reload();
+ else if (sender == stop_button_)
+ shell_->Stop();
+ }
+
+ // Overridden from WidgetDelegateView
+ virtual bool CanResize() const OVERRIDE { return true; }
+ virtual bool CanMaximize() const OVERRIDE { return true; }
+ virtual string16 GetWindowTitle() const OVERRIDE {
+ return title_;
+ }
+ virtual void WindowClosing() OVERRIDE {
+ if (shell_) {
+ delete shell_;
+ shell_ = NULL;
+ }
+ }
+ virtual View* GetContentsView() OVERRIDE { return this; }
+
+ // Overridden from View
+ virtual void ViewHierarchyChanged(
+ const ViewHierarchyChangedDetails& details) OVERRIDE {
+ if (details.is_add && details.child == this) {
+ InitShellWindow();
+ }
+ }
+
+ private:
+ // Hold a reference of Shell for deleting it when the window is closing
+ Shell* shell_;
+
+ // Window title
+ string16 title_;
+
+ // Toolbar view contains forward/backward/reload button and URL entry
+ View* toolbar_view_;
+ views::LabelButton* back_button_;
+ views::LabelButton* forward_button_;
+ views::LabelButton* refresh_button_;
+ views::LabelButton* stop_button_;
+ views::Textfield* url_entry_;
+
+ // Contents view contains the web contents view
+ View* contents_view_;
+ views::WebView* web_view_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellWindowDelegateView);
+};
+
+} // namespace
+
+#if defined(OS_CHROMEOS)
+MinimalShell* Shell::minimal_shell_ = NULL;
+#endif
+views::ViewsDelegate* Shell::views_delegate_ = NULL;
+
+// static
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+#if defined(OS_CHROMEOS)
+ chromeos::DBusThreadManager::Initialize();
+ gfx::Screen::SetScreenInstance(
+ gfx::SCREEN_TYPE_NATIVE, aura::TestScreen::Create());
+ minimal_shell_ = new content::MinimalShell(default_window_size);
+#else
+ gfx::Screen::SetScreenInstance(
+ gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen());
+#endif
+ views_delegate_ = new ShellViewsDelegateAura();
+}
+
+void Shell::PlatformExit() {
+#if defined(OS_CHROMEOS)
+ if (minimal_shell_)
+ delete minimal_shell_;
+#endif
+ if (views_delegate_)
+ delete views_delegate_;
+#if defined(OS_CHROMEOS)
+ chromeos::DBusThreadManager::Shutdown();
+#endif
+ aura::Env::DeleteInstance();
+}
+
+void Shell::PlatformCleanUp() {
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+ if (control == BACK_BUTTON) {
+ delegate_view->EnableUIControl(ShellWindowDelegateView::BACK_BUTTON,
+ is_enabled);
+ } else if (control == FORWARD_BUTTON) {
+ delegate_view->EnableUIControl(ShellWindowDelegateView::FORWARD_BUTTON,
+ is_enabled);
+ } else if (control == STOP_BUTTON) {
+ delegate_view->EnableUIControl(ShellWindowDelegateView::STOP_BUTTON,
+ is_enabled);
+ }
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+ delegate_view->SetAddressBarURL(url);
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+#if defined(OS_CHROMEOS)
+ window_widget_ =
+ views::Widget::CreateWindowWithContextAndBounds(
+ new ShellWindowDelegateView(this),
+ minimal_shell_->GetDefaultParent(NULL, NULL, gfx::Rect()),
+ gfx::Rect(0, 0, width, height));
+#else
+ window_widget_ =
+ views::Widget::CreateWindowWithBounds(new ShellWindowDelegateView(this),
+ gfx::Rect(0, 0, width, height));
+#endif
+
+ window_ = window_widget_->GetNativeWindow();
+ // Call ShowRootWindow on RootWindow created by MinimalShell without
+ // which XWindow owned by RootWindow doesn't get mapped.
+ window_->GetRootWindow()->ShowRootWindow();
+ window_widget_->Show();
+}
+
+void Shell::PlatformSetContents() {
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+ delegate_view->SetWebContents(web_contents_.get());
+}
+
+void Shell::PlatformResizeSubViews() {
+}
+
+void Shell::Close() {
+ window_widget_->Close();
+}
+
+void Shell::PlatformSetTitle(const string16& title) {
+ ShellWindowDelegateView* delegate_view =
+ static_cast<ShellWindowDelegateView*>(window_widget_->widget_delegate());
+ delegate_view->SetWindowTitle(title);
+ window_widget_->UpdateWindowTitle();
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_browser_context.cc b/content/shell/browser/shell_browser_context.cc
new file mode 100644
index 0000000..c6dbb99
--- /dev/null
+++ b/content/shell/browser/shell_browser_context.cc
@@ -0,0 +1,215 @@
+// 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_browser_context.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/environment.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/path_service.h"
+#include "base/threading/thread.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/resource_context.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_switches.h"
+#include "content/shell/browser/shell_download_manager_delegate.h"
+#include "content/shell/browser/shell_url_request_context_getter.h"
+#include "content/shell/common/shell_switches.h"
+
+#if defined(OS_WIN)
+#include "base/base_paths_win.h"
+#elif defined(OS_LINUX)
+#include "base/nix/xdg_util.h"
+#elif defined(OS_MACOSX)
+#include "base/base_paths_mac.h"
+#endif
+
+namespace content {
+
+class ShellBrowserContext::ShellResourceContext : public ResourceContext {
+ public:
+ ShellResourceContext() : getter_(NULL) {}
+ virtual ~ShellResourceContext() {}
+
+ // ResourceContext implementation:
+ virtual net::HostResolver* GetHostResolver() OVERRIDE {
+ CHECK(getter_);
+ return getter_->host_resolver();
+ }
+ virtual net::URLRequestContext* GetRequestContext() OVERRIDE {
+ CHECK(getter_);
+ return getter_->GetURLRequestContext();
+ }
+ virtual bool AllowMicAccess(const GURL& origin) OVERRIDE {
+ return false;
+ }
+ virtual bool AllowCameraAccess(const GURL& origin) OVERRIDE {
+ return false;
+ }
+
+ void set_url_request_context_getter(ShellURLRequestContextGetter* getter) {
+ getter_ = getter;
+ }
+
+ private:
+ ShellURLRequestContextGetter* getter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellResourceContext);
+};
+
+ShellBrowserContext::ShellBrowserContext(bool off_the_record,
+ net::NetLog* net_log)
+ : off_the_record_(off_the_record),
+ net_log_(net_log),
+ ignore_certificate_errors_(false),
+ resource_context_(new ShellResourceContext) {
+ InitWhileIOAllowed();
+}
+
+ShellBrowserContext::~ShellBrowserContext() {
+ if (resource_context_) {
+ BrowserThread::DeleteSoon(
+ BrowserThread::IO, FROM_HERE, resource_context_.release());
+ }
+}
+
+void ShellBrowserContext::InitWhileIOAllowed() {
+ CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+ if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors) ||
+ cmd_line->HasSwitch(switches::kDumpRenderTree)) {
+ ignore_certificate_errors_ = true;
+ }
+ if (cmd_line->HasSwitch(switches::kContentShellDataPath)) {
+ path_ = cmd_line->GetSwitchValuePath(switches::kContentShellDataPath);
+ return;
+ }
+#if defined(OS_WIN)
+ CHECK(PathService::Get(base::DIR_LOCAL_APP_DATA, &path_));
+ path_ = path_.Append(std::wstring(L"content_shell"));
+#elif defined(OS_LINUX)
+ scoped_ptr<base::Environment> env(base::Environment::Create());
+ base::FilePath config_dir(
+ base::nix::GetXDGDirectory(env.get(),
+ base::nix::kXdgConfigHomeEnvVar,
+ base::nix::kDotConfigDir));
+ path_ = config_dir.Append("content_shell");
+#elif defined(OS_MACOSX)
+ CHECK(PathService::Get(base::DIR_APP_DATA, &path_));
+ path_ = path_.Append("Chromium Content Shell");
+#elif defined(OS_ANDROID)
+ CHECK(PathService::Get(base::DIR_ANDROID_APP_DATA, &path_));
+ path_ = path_.Append(FILE_PATH_LITERAL("content_shell"));
+#else
+ NOTIMPLEMENTED();
+#endif
+
+ if (!base::PathExists(path_))
+ file_util::CreateDirectory(path_);
+}
+
+base::FilePath ShellBrowserContext::GetPath() const {
+ return path_;
+}
+
+bool ShellBrowserContext::IsOffTheRecord() const {
+ return off_the_record_;
+}
+
+DownloadManagerDelegate* ShellBrowserContext::GetDownloadManagerDelegate() {
+ DownloadManager* manager = BrowserContext::GetDownloadManager(this);
+
+ if (!download_manager_delegate_.get()) {
+ download_manager_delegate_ = new ShellDownloadManagerDelegate();
+ download_manager_delegate_->SetDownloadManager(manager);
+ CommandLine* cmd_line = CommandLine::ForCurrentProcess();
+ if (cmd_line->HasSwitch(switches::kDumpRenderTree)) {
+ download_manager_delegate_->SetDownloadBehaviorForTesting(
+ path_.Append(FILE_PATH_LITERAL("downloads")));
+ }
+ }
+
+ return download_manager_delegate_.get();
+}
+
+net::URLRequestContextGetter* ShellBrowserContext::GetRequestContext() {
+ return GetDefaultStoragePartition(this)->GetURLRequestContext();
+}
+
+net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContext(
+ ProtocolHandlerMap* protocol_handlers) {
+ DCHECK(!url_request_getter_.get());
+ url_request_getter_ = new ShellURLRequestContextGetter(
+ ignore_certificate_errors_,
+ GetPath(),
+ BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::IO),
+ BrowserThread::UnsafeGetMessageLoopForThread(BrowserThread::FILE),
+ protocol_handlers,
+ net_log_);
+ resource_context_->set_url_request_context_getter(url_request_getter_.get());
+ return url_request_getter_.get();
+}
+
+net::URLRequestContextGetter*
+ ShellBrowserContext::GetRequestContextForRenderProcess(
+ int renderer_child_id) {
+ return GetRequestContext();
+}
+
+net::URLRequestContextGetter*
+ ShellBrowserContext::GetMediaRequestContext() {
+ return GetRequestContext();
+}
+
+net::URLRequestContextGetter*
+ ShellBrowserContext::GetMediaRequestContextForRenderProcess(
+ int renderer_child_id) {
+ return GetRequestContext();
+}
+
+net::URLRequestContextGetter*
+ ShellBrowserContext::GetMediaRequestContextForStoragePartition(
+ const base::FilePath& partition_path,
+ bool in_memory) {
+ return GetRequestContext();
+}
+
+void ShellBrowserContext::RequestMIDISysExPermission(
+ int render_process_id,
+ int render_view_id,
+ const GURL& requesting_frame,
+ const MIDISysExPermissionCallback& callback) {
+ // Always reject requests for LayoutTests for now.
+ // TODO(toyoshim): Make it programmable to improve test coverage.
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+ callback.Run(false);
+ return;
+ }
+ // TODO(toyoshim): Implement. http://crbug.com/257618 .
+ callback.Run(false);
+}
+
+net::URLRequestContextGetter*
+ ShellBrowserContext::CreateRequestContextForStoragePartition(
+ const base::FilePath& partition_path,
+ bool in_memory,
+ ProtocolHandlerMap* protocol_handlers) {
+ return NULL;
+}
+
+ResourceContext* ShellBrowserContext::GetResourceContext() {
+ return resource_context_.get();
+}
+
+GeolocationPermissionContext*
+ ShellBrowserContext::GetGeolocationPermissionContext() {
+ return NULL;
+}
+
+quota::SpecialStoragePolicy* ShellBrowserContext::GetSpecialStoragePolicy() {
+ return NULL;
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_browser_context.h b/content/shell/browser/shell_browser_context.h
new file mode 100644
index 0000000..ec71591
--- /dev/null
+++ b/content/shell/browser/shell_browser_context.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_
+#define CONTENT_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/content_browser_client.h"
+#include "net/url_request/url_request_job_factory.h"
+
+namespace net {
+class NetLog;
+}
+
+namespace content {
+
+class DownloadManagerDelegate;
+class ResourceContext;
+class ShellDownloadManagerDelegate;
+class ShellURLRequestContextGetter;
+
+class ShellBrowserContext : public BrowserContext {
+ public:
+ ShellBrowserContext(bool off_the_record, net::NetLog* net_log);
+ virtual ~ShellBrowserContext();
+
+ // BrowserContext implementation.
+ virtual base::FilePath GetPath() const OVERRIDE;
+ virtual bool IsOffTheRecord() const OVERRIDE;
+ virtual DownloadManagerDelegate* GetDownloadManagerDelegate() OVERRIDE;
+ virtual net::URLRequestContextGetter* GetRequestContext() OVERRIDE;
+ virtual net::URLRequestContextGetter* GetRequestContextForRenderProcess(
+ int renderer_child_id) OVERRIDE;
+ virtual net::URLRequestContextGetter* GetMediaRequestContext() OVERRIDE;
+ virtual net::URLRequestContextGetter* GetMediaRequestContextForRenderProcess(
+ int renderer_child_id) OVERRIDE;
+ virtual net::URLRequestContextGetter*
+ GetMediaRequestContextForStoragePartition(
+ const base::FilePath& partition_path,
+ bool in_memory) OVERRIDE;
+ virtual void RequestMIDISysExPermission(
+ int render_process_id,
+ int render_view_id,
+ const GURL& requesting_frame,
+ const MIDISysExPermissionCallback& callback) OVERRIDE;
+ virtual ResourceContext* GetResourceContext() OVERRIDE;
+ virtual GeolocationPermissionContext*
+ GetGeolocationPermissionContext() OVERRIDE;
+ virtual quota::SpecialStoragePolicy* GetSpecialStoragePolicy() OVERRIDE;
+
+ net::URLRequestContextGetter* CreateRequestContext(
+ ProtocolHandlerMap* protocol_handlers);
+ net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
+ const base::FilePath& partition_path,
+ bool in_memory,
+ ProtocolHandlerMap* protocol_handlers);
+
+ private:
+ class ShellResourceContext;
+
+ // Performs initialization of the ShellBrowserContext while IO is still
+ // allowed on the current thread.
+ void InitWhileIOAllowed();
+
+ bool off_the_record_;
+ net::NetLog* net_log_;
+ bool ignore_certificate_errors_;
+ base::FilePath path_;
+ scoped_ptr<ShellResourceContext> resource_context_;
+ scoped_refptr<ShellDownloadManagerDelegate> download_manager_delegate_;
+ scoped_refptr<ShellURLRequestContextGetter> url_request_getter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellBrowserContext);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_BROWSER_CONTEXT_H_
diff --git a/content/shell/browser/shell_browser_main.cc b/content/shell/browser/shell_browser_main.cc
new file mode 100644
index 0000000..ac520d6
--- /dev/null
+++ b/content/shell/browser/shell_browser_main.cc
@@ -0,0 +1,220 @@
+// 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_browser_main.h"
+
+#include <iostream>
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/files/file_path.h"
+#include "base/files/scoped_temp_dir.h"
+#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/strings/sys_string_conversions.h"
+#include "base/strings/utf_string_conversions.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/browser/browser_main_runner.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_switches.h"
+#include "content/shell/common/webkit_test_helpers.h"
+#include "net/base/net_util.h"
+#include "webkit/support/webkit_support.h"
+
+#if defined(OS_ANDROID)
+#include "base/run_loop.h"
+#include "content/shell/browser/shell_layout_tests_android.h"
+#endif
+
+namespace {
+
+GURL GetURLForLayoutTest(const std::string& test_name,
+ base::FilePath* current_working_directory,
+ bool* enable_pixel_dumping,
+ std::string* expected_pixel_hash) {
+ // A test name is formated like file:///path/to/test'--pixel-test'pixelhash
+ std::string path_or_url = test_name;
+ std::string pixel_switch;
+ std::string pixel_hash;
+ std::string::size_type separator_position = path_or_url.find('\'');
+ if (separator_position != std::string::npos) {
+ pixel_switch = path_or_url.substr(separator_position + 1);
+ path_or_url.erase(separator_position);
+ }
+ separator_position = pixel_switch.find('\'');
+ if (separator_position != std::string::npos) {
+ pixel_hash = pixel_switch.substr(separator_position + 1);
+ pixel_switch.erase(separator_position);
+ }
+ if (enable_pixel_dumping) {
+ *enable_pixel_dumping =
+ (pixel_switch == "--pixel-test" || pixel_switch == "-p");
+ }
+ if (expected_pixel_hash)
+ *expected_pixel_hash = pixel_hash;
+
+ GURL test_url;
+#if defined(OS_ANDROID)
+ if (content::GetTestUrlForAndroid(path_or_url, &test_url))
+ return test_url;
+#endif
+
+ test_url = GURL(path_or_url);
+ if (!(test_url.is_valid() && test_url.has_scheme())) {
+ // We're outside of the message loop here, and this is a test.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+#if defined(OS_WIN)
+ std::wstring wide_path_or_url =
+ base::SysNativeMBToWide(path_or_url);
+ base::FilePath local_file(wide_path_or_url);
+#else
+ base::FilePath local_file(path_or_url);
+#endif
+ if (!base::PathExists(local_file)) {
+ local_file = content::GetWebKitRootDirFilePath()
+ .Append(FILE_PATH_LITERAL("LayoutTests")).Append(local_file);
+ }
+ test_url = net::FilePathToFileURL(base::MakeAbsoluteFilePath(local_file));
+ }
+ base::FilePath local_path;
+ if (current_working_directory) {
+ // We're outside of the message loop here, and this is a test.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ if (net::FileURLToFilePath(test_url, &local_path))
+ *current_working_directory = local_path.DirName();
+ else
+ file_util::GetCurrentDirectory(current_working_directory);
+ }
+ return test_url;
+}
+
+bool GetNextTest(const CommandLine::StringVector& args,
+ size_t* position,
+ std::string* test) {
+ if (*position >= args.size())
+ return false;
+ if (args[*position] == FILE_PATH_LITERAL("-"))
+ return !!std::getline(std::cin, *test, '\n');
+#if defined(OS_WIN)
+ *test = WideToUTF8(args[(*position)++]);
+#else
+ *test = args[(*position)++];
+#endif
+ return true;
+}
+
+} // namespace
+
+// Main routine for running as the Browser process.
+int ShellBrowserMain(
+ const content::MainFunctionParams& parameters,
+ const scoped_ptr<content::BrowserMainRunner>& main_runner) {
+ bool layout_test_mode =
+ CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
+ base::ScopedTempDir browser_context_path_for_layout_tests;
+
+ if (layout_test_mode) {
+ CHECK(browser_context_path_for_layout_tests.CreateUniqueTempDir());
+ CHECK(!browser_context_path_for_layout_tests.path().MaybeAsASCII().empty());
+ CommandLine::ForCurrentProcess()->AppendSwitchASCII(
+ switches::kContentShellDataPath,
+ browser_context_path_for_layout_tests.path().MaybeAsASCII());
+
+#if defined(OS_ANDROID)
+ content::EnsureInitializeForAndroidLayoutTests();
+#endif
+ }
+
+ int exit_code = main_runner->Initialize(parameters);
+ DCHECK_LT(exit_code, 0)
+ << "BrowserMainRunner::Initialize failed in ShellBrowserMain";
+
+ if (exit_code >= 0)
+ return exit_code;
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kCheckLayoutTestSysDeps)) {
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::MessageLoop::QuitClosure());
+ main_runner->Run();
+ content::Shell::CloseAllWindows();
+ main_runner->Shutdown();
+ return 0;
+ }
+
+ if (layout_test_mode) {
+ content::WebKitTestController test_controller;
+ {
+ // We're outside of the message loop here, and this is a test.
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ base::FilePath temp_path;
+ file_util::GetTempDir(&temp_path);
+ test_controller.SetTempPath(temp_path);
+ }
+ std::string test_string;
+ CommandLine::StringVector args =
+ CommandLine::ForCurrentProcess()->GetArgs();
+ size_t command_line_position = 0;
+ bool ran_at_least_once = false;
+
+#if defined(OS_ANDROID)
+ std::cout << "#READY\n";
+ std::cout.flush();
+#endif
+
+ while (GetNextTest(args, &command_line_position, &test_string)) {
+ if (test_string.empty())
+ continue;
+ if (test_string == "QUIT")
+ break;
+
+ bool enable_pixel_dumps;
+ std::string pixel_hash;
+ base::FilePath cwd;
+ GURL test_url = GetURLForLayoutTest(
+ test_string, &cwd, &enable_pixel_dumps, &pixel_hash);
+ if (!content::WebKitTestController::Get()->PrepareForLayoutTest(
+ test_url, cwd, enable_pixel_dumps, pixel_hash)) {
+ break;
+ }
+
+ ran_at_least_once = true;
+#if defined(OS_ANDROID)
+ // The message loop on Android is provided by the system, and does not
+ // offer a blocking Run() method. For layout tests, use a nested loop
+ // together with a base::RunLoop so it can block until a QuitClosure.
+ base::RunLoop run_loop;
+ run_loop.Run();
+#else
+ main_runner->Run();
+#endif
+
+ if (!content::WebKitTestController::Get()->ResetAfterLayoutTest())
+ break;
+ }
+ if (!ran_at_least_once) {
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::MessageLoop::QuitClosure());
+ main_runner->Run();
+ }
+
+#if defined(OS_ANDROID)
+ // Android should only execute Shutdown() here when running layout tests.
+ main_runner->Shutdown();
+#endif
+
+ exit_code = 0;
+ }
+
+#if !defined(OS_ANDROID)
+ if (!layout_test_mode)
+ exit_code = main_runner->Run();
+
+ main_runner->Shutdown();
+#endif
+
+ return exit_code;
+}
diff --git a/content/shell/browser/shell_browser_main.h b/content/shell/browser/shell_browser_main.h
new file mode 100644
index 0000000..d361fa3
--- /dev/null
+++ b/content/shell/browser/shell_browser_main.h
@@ -0,0 +1,19 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_H_
+#define CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_H_
+
+#include "base/memory/scoped_ptr.h"
+
+namespace content {
+class BrowserMainRunner;
+struct MainFunctionParams;
+}
+
+int ShellBrowserMain(
+ const content::MainFunctionParams& parameters,
+ const scoped_ptr<content::BrowserMainRunner>& main_runner);
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_H_
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc
new file mode 100644
index 0000000..6f7da00
--- /dev/null
+++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -0,0 +1,175 @@
+// 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_browser_main_parts.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/message_loop/message_loop.h"
+#include "base/threading/thread.h"
+#include "base/threading/thread_restrictions.h"
+#include "cc/base/switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/main_function_params.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_devtools_delegate.h"
+#include "content/shell/browser/shell_net_log.h"
+#include "content/shell/common/shell_switches.h"
+#include "grit/net_resources.h"
+#include "net/base/net_module.h"
+#include "net/base/net_util.h"
+#include "ui/base/resource/resource_bundle.h"
+#include "url/gurl.h"
+#include "webkit/browser/quota/quota_manager.h"
+
+#if defined(ENABLE_PLUGINS)
+#include "content/public/browser/plugin_service.h"
+#include "content/shell/browser/shell_plugin_service_filter.h"
+#endif
+
+#if defined(OS_ANDROID)
+#include "net/android/network_change_notifier_factory_android.h"
+#include "net/base/network_change_notifier.h"
+#endif
+
+#if defined(USE_AURA) && defined(USE_X11)
+#include "ui/base/touch/touch_factory_x11.h"
+#endif
+
+namespace content {
+
+namespace {
+
+// Default quota for each origin is 5MB.
+const int kDefaultLayoutTestQuotaBytes = 5 * 1024 * 1024;
+
+GURL GetStartupURL() {
+ CommandLine* command_line = CommandLine::ForCurrentProcess();
+ if (command_line->HasSwitch(switches::kContentBrowserTest))
+ return GURL();
+ const CommandLine::StringVector& args = command_line->GetArgs();
+
+#if defined(OS_ANDROID)
+ // Delay renderer creation on Android until surface is ready.
+ return GURL();
+#endif
+
+ if (args.empty())
+ return GURL("http://www.google.com/");
+
+ GURL url(args[0]);
+ if (url.is_valid() && url.has_scheme())
+ return url;
+
+ return net::FilePathToFileURL(base::FilePath(args[0]));
+}
+
+base::StringPiece PlatformResourceProvider(int key) {
+ if (key == IDR_DIR_HEADER_HTML) {
+ base::StringPiece html_data =
+ ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_DIR_HEADER_HTML);
+ return html_data;
+ }
+ return base::StringPiece();
+}
+
+} // namespace
+
+ShellBrowserMainParts::ShellBrowserMainParts(
+ const MainFunctionParams& parameters)
+ : BrowserMainParts(), parameters_(parameters), run_message_loop_(true) {}
+
+ShellBrowserMainParts::~ShellBrowserMainParts() {
+}
+
+#if !defined(OS_MACOSX)
+void ShellBrowserMainParts::PreMainMessageLoopStart() {
+#if defined(USE_AURA) && defined(USE_X11)
+ ui::TouchFactory::SetTouchDeviceListFromCommandLine();
+#endif
+}
+#endif
+
+void ShellBrowserMainParts::PostMainMessageLoopStart() {
+#if defined(OS_ANDROID)
+ base::MessageLoopForUI::current()->Start();
+#endif
+}
+
+void ShellBrowserMainParts::PreEarlyInitialization() {
+#if defined(OS_ANDROID)
+ net::NetworkChangeNotifier::SetFactory(
+ new net::NetworkChangeNotifierFactoryAndroid());
+
+ CommandLine::ForCurrentProcess()->AppendSwitch(
+ cc::switches::kCompositeToMailbox);
+#endif
+}
+
+void ShellBrowserMainParts::PreMainMessageLoopRun() {
+ net_log_.reset(new ShellNetLog());
+ browser_context_.reset(new ShellBrowserContext(false, net_log_.get()));
+ off_the_record_browser_context_.reset(
+ new ShellBrowserContext(true, net_log_.get()));
+
+ Shell::Initialize();
+ net::NetModule::SetResourceProvider(PlatformResourceProvider);
+
+ devtools_delegate_.reset(new ShellDevToolsDelegate(browser_context_.get()));
+
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+ Shell::CreateNewWindow(browser_context_.get(),
+ GetStartupURL(),
+ NULL,
+ MSG_ROUTING_NONE,
+ gfx::Size());
+ }
+
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+ quota::QuotaManager* quota_manager =
+ BrowserContext::GetDefaultStoragePartition(browser_context())
+ ->GetQuotaManager();
+ BrowserThread::PostTask(
+ BrowserThread::IO,
+ FROM_HERE,
+ base::Bind(&quota::QuotaManager::SetTemporaryGlobalOverrideQuota,
+ quota_manager,
+ kDefaultLayoutTestQuotaBytes *
+ quota::QuotaManager::kPerHostTemporaryPortion,
+ quota::QuotaCallback()));
+#if defined(ENABLE_PLUGINS)
+ PluginService* plugin_service = PluginService::GetInstance();
+ plugin_service_filter_.reset(new ShellPluginServiceFilter);
+ plugin_service->SetFilter(plugin_service_filter_.get());
+#endif
+ }
+
+ if (parameters_.ui_task) {
+ parameters_.ui_task->Run();
+ delete parameters_.ui_task;
+ run_message_loop_ = false;
+ }
+}
+
+bool ShellBrowserMainParts::MainMessageLoopRun(int* result_code) {
+ return !run_message_loop_;
+}
+
+void ShellBrowserMainParts::PostMainMessageLoopRun() {
+#if defined(USE_AURA)
+ Shell::PlatformExit();
+#endif
+ if (devtools_delegate_)
+ devtools_delegate_->Stop();
+ browser_context_.reset();
+ off_the_record_browser_context_.reset();
+}
+
+} // namespace
diff --git a/content/shell/browser/shell_browser_main_parts.h b/content/shell/browser/shell_browser_main_parts.h
new file mode 100644
index 0000000..990e1c5
--- /dev/null
+++ b/content/shell/browser/shell_browser_main_parts.h
@@ -0,0 +1,70 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_
+#define CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_
+
+#include "base/basictypes.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/browser_main_parts.h"
+#include "content/public/common/main_function_params.h"
+
+namespace base {
+class Thread;
+}
+
+namespace net {
+class NetLog;
+}
+
+namespace content {
+
+class ShellBrowserContext;
+class ShellDevToolsDelegate;
+class ShellPluginServiceFilter;
+
+class ShellBrowserMainParts : public BrowserMainParts {
+ public:
+ explicit ShellBrowserMainParts(const MainFunctionParams& parameters);
+ virtual ~ShellBrowserMainParts();
+
+ // BrowserMainParts overrides.
+ virtual void PreEarlyInitialization() OVERRIDE;
+ virtual void PreMainMessageLoopStart() OVERRIDE;
+ virtual void PostMainMessageLoopStart() OVERRIDE;
+ virtual void PreMainMessageLoopRun() OVERRIDE;
+ virtual bool MainMessageLoopRun(int* result_code) OVERRIDE;
+ virtual void PostMainMessageLoopRun() OVERRIDE;
+
+ ShellDevToolsDelegate* devtools_delegate() {
+ return devtools_delegate_.get();
+ }
+
+ ShellBrowserContext* browser_context() { return browser_context_.get(); }
+ ShellBrowserContext* off_the_record_browser_context() {
+ return off_the_record_browser_context_.get();
+ }
+
+ net::NetLog* net_log() { return net_log_.get(); }
+
+ private:
+ scoped_ptr<net::NetLog> net_log_;
+ scoped_ptr<ShellBrowserContext> browser_context_;
+ scoped_ptr<ShellBrowserContext> off_the_record_browser_context_;
+
+ // For running content_browsertests.
+ const MainFunctionParams parameters_;
+ bool run_message_loop_;
+
+ scoped_ptr<ShellDevToolsDelegate> devtools_delegate_;
+#if defined(ENABLE_PLUGINS)
+ scoped_ptr<ShellPluginServiceFilter> plugin_service_filter_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ShellBrowserMainParts);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_BROWSER_MAIN_PARTS_H_
diff --git a/content/shell/browser/shell_browser_main_parts_mac.mm b/content/shell/browser/shell_browser_main_parts_mac.mm
new file mode 100644
index 0000000..a933705
--- /dev/null
+++ b/content/shell/browser/shell_browser_main_parts_mac.mm
@@ -0,0 +1,25 @@
+// 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_browser_main_parts.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/mac/bundle_locations.h"
+#include "base/mac/scoped_nsobject.h"
+#include "content/shell/browser/shell_application_mac.h"
+
+namespace content {
+
+void ShellBrowserMainParts::PreMainMessageLoopStart() {
+ // Force the NSApplication subclass to be used.
+ [ShellCrApplication sharedApplication];
+
+ base::scoped_nsobject<NSNib> nib(
+ [[NSNib alloc] initWithNibNamed:@"MainMenu"
+ bundle:base::mac::FrameworkBundle()]);
+ [nib instantiateNibWithOwner:NSApp topLevelObjects:nil];
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_content_browser_client.cc b/content/shell/browser/shell_content_browser_client.cc
new file mode 100644
index 0000000..715eafd
--- /dev/null
+++ b/content/shell/browser/shell_content_browser_client.cc
@@ -0,0 +1,275 @@
+// 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_content_browser_client.h"
+
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/resource_dispatcher_host.h"
+#include "content/public/browser/storage_partition.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_browser_main_parts.h"
+#include "content/shell/browser/shell_devtools_delegate.h"
+#include "content/shell/browser/shell_message_filter.h"
+#include "content/shell/browser/shell_net_log.h"
+#include "content/shell/browser/shell_quota_permission_context.h"
+#include "content/shell/browser/shell_resource_dispatcher_host_delegate.h"
+#include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_messages.h"
+#include "content/shell/common/shell_switches.h"
+#include "content/shell/common/webkit_test_helpers.h"
+#include "content/shell/geolocation/shell_access_token_store.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "url/gurl.h"
+#include "webkit/common/webpreferences.h"
+
+#if defined(OS_ANDROID)
+#include "base/android/path_utils.h"
+#include "base/path_service.h"
+#include "base/platform_file.h"
+#include "content/shell/android/shell_descriptors.h"
+#endif
+
+namespace content {
+
+namespace {
+
+ShellContentBrowserClient* g_browser_client;
+bool g_swap_processes_for_redirect = false;
+
+} // namespace
+
+ShellContentBrowserClient* ShellContentBrowserClient::Get() {
+ return g_browser_client;
+}
+
+void ShellContentBrowserClient::SetSwapProcessesForRedirect(bool swap) {
+ g_swap_processes_for_redirect = swap;
+}
+
+ShellContentBrowserClient::ShellContentBrowserClient()
+ : shell_browser_main_parts_(NULL) {
+ DCHECK(!g_browser_client);
+ g_browser_client = this;
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+ webkit_source_dir_ = GetWebKitRootDirFilePath();
+}
+
+ShellContentBrowserClient::~ShellContentBrowserClient() {
+ g_browser_client = NULL;
+}
+
+BrowserMainParts* ShellContentBrowserClient::CreateBrowserMainParts(
+ const MainFunctionParams& parameters) {
+ shell_browser_main_parts_ = new ShellBrowserMainParts(parameters);
+ return shell_browser_main_parts_;
+}
+
+void ShellContentBrowserClient::RenderProcessHostCreated(
+ RenderProcessHost* host) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+ host->GetChannel()->AddFilter(new ShellMessageFilter(
+ host->GetID(),
+ BrowserContext::GetDefaultStoragePartition(browser_context())
+ ->GetDatabaseTracker(),
+ BrowserContext::GetDefaultStoragePartition(browser_context())
+ ->GetQuotaManager(),
+ BrowserContext::GetDefaultStoragePartition(browser_context())
+ ->GetURLRequestContext()));
+ host->Send(new ShellViewMsg_SetWebKitSourceDir(webkit_source_dir_));
+ registrar_.Add(this,
+ NOTIFICATION_RENDERER_PROCESS_CREATED,
+ Source<RenderProcessHost>(host));
+ registrar_.Add(this,
+ NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+ Source<RenderProcessHost>(host));
+}
+
+net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext(
+ BrowserContext* content_browser_context,
+ ProtocolHandlerMap* protocol_handlers) {
+ ShellBrowserContext* shell_browser_context =
+ ShellBrowserContextForBrowserContext(content_browser_context);
+ return shell_browser_context->CreateRequestContext(protocol_handlers);
+}
+
+net::URLRequestContextGetter*
+ShellContentBrowserClient::CreateRequestContextForStoragePartition(
+ BrowserContext* content_browser_context,
+ const base::FilePath& partition_path,
+ bool in_memory,
+ ProtocolHandlerMap* protocol_handlers) {
+ ShellBrowserContext* shell_browser_context =
+ ShellBrowserContextForBrowserContext(content_browser_context);
+ return shell_browser_context->CreateRequestContextForStoragePartition(
+ partition_path, in_memory, protocol_handlers);
+}
+
+bool ShellContentBrowserClient::IsHandledURL(const GURL& url) {
+ if (!url.is_valid())
+ return false;
+ DCHECK_EQ(url.scheme(), StringToLowerASCII(url.scheme()));
+ // Keep in sync with ProtocolHandlers added by
+ // ShellURLRequestContextGetter::GetURLRequestContext().
+ static const char* const kProtocolList[] = {
+ chrome::kBlobScheme,
+ chrome::kFileSystemScheme,
+ chrome::kChromeUIScheme,
+ chrome::kChromeDevToolsScheme,
+ chrome::kDataScheme,
+ chrome::kFileScheme,
+ };
+ for (size_t i = 0; i < arraysize(kProtocolList); ++i) {
+ if (url.scheme() == kProtocolList[i])
+ return true;
+ }
+ return false;
+}
+
+void ShellContentBrowserClient::AppendExtraCommandLineSwitches(
+ CommandLine* command_line, int child_process_id) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ command_line->AppendSwitch(switches::kDumpRenderTree);
+ if (CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kExposeInternalsForTesting))
+ command_line->AppendSwitch(switches::kExposeInternalsForTesting);
+}
+
+void ShellContentBrowserClient::OverrideWebkitPrefs(
+ RenderViewHost* render_view_host,
+ const GURL& url,
+ WebPreferences* prefs) {
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+ WebKitTestController::Get()->OverrideWebkitPrefs(prefs);
+}
+
+void ShellContentBrowserClient::ResourceDispatcherHostCreated() {
+ resource_dispatcher_host_delegate_.reset(
+ new ShellResourceDispatcherHostDelegate());
+ ResourceDispatcherHost::Get()->SetDelegate(
+ resource_dispatcher_host_delegate_.get());
+}
+
+std::string ShellContentBrowserClient::GetDefaultDownloadName() {
+ return "download";
+}
+
+bool ShellContentBrowserClient::SupportsBrowserPlugin(
+ content::BrowserContext* browser_context, const GURL& url) {
+ return CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kEnableBrowserPluginForAllViewTypes);
+}
+
+WebContentsViewDelegate* ShellContentBrowserClient::GetWebContentsViewDelegate(
+ WebContents* web_contents) {
+#if !defined(USE_AURA)
+ return CreateShellWebContentsViewDelegate(web_contents);
+#else
+ return NULL;
+#endif
+}
+
+QuotaPermissionContext*
+ShellContentBrowserClient::CreateQuotaPermissionContext() {
+ return new ShellQuotaPermissionContext();
+}
+
+net::NetLog* ShellContentBrowserClient::GetNetLog() {
+ return shell_browser_main_parts_->net_log();
+}
+
+bool ShellContentBrowserClient::ShouldSwapProcessesForRedirect(
+ ResourceContext* resource_context,
+ const GURL& current_url,
+ const GURL& new_url) {
+ return g_swap_processes_for_redirect;
+}
+
+#if defined(OS_ANDROID)
+void ShellContentBrowserClient::GetAdditionalMappedFilesForChildProcess(
+ const CommandLine& command_line,
+ int child_process_id,
+ std::vector<content::FileDescriptorInfo>* mappings) {
+ int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ;
+ base::FilePath pak_file;
+ bool r = PathService::Get(base::DIR_ANDROID_APP_DATA, &pak_file);
+ CHECK(r);
+ pak_file = pak_file.Append(FILE_PATH_LITERAL("paks"));
+ pak_file = pak_file.Append(FILE_PATH_LITERAL("content_shell.pak"));
+
+ base::PlatformFile f =
+ base::CreatePlatformFile(pak_file, flags, NULL, NULL);
+ if (f == base::kInvalidPlatformFileValue) {
+ NOTREACHED() << "Failed to open file when creating renderer process: "
+ << "content_shell.pak";
+ }
+ mappings->push_back(
+ content::FileDescriptorInfo(kShellPakDescriptor,
+ base::FileDescriptor(f, true)));
+}
+#endif
+
+void ShellContentBrowserClient::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ switch (type) {
+ case NOTIFICATION_RENDERER_PROCESS_CREATED: {
+ registrar_.Remove(this,
+ NOTIFICATION_RENDERER_PROCESS_CREATED,
+ source);
+ registrar_.Remove(this,
+ NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+ source);
+ break;
+ }
+
+ case NOTIFICATION_RENDERER_PROCESS_TERMINATED: {
+ registrar_.Remove(this,
+ NOTIFICATION_RENDERER_PROCESS_CREATED,
+ source);
+ registrar_.Remove(this,
+ NOTIFICATION_RENDERER_PROCESS_TERMINATED,
+ source);
+ break;
+ }
+
+ default:
+ NOTREACHED();
+ }
+}
+
+ShellBrowserContext* ShellContentBrowserClient::browser_context() {
+ return shell_browser_main_parts_->browser_context();
+}
+
+ShellBrowserContext*
+ ShellContentBrowserClient::off_the_record_browser_context() {
+ return shell_browser_main_parts_->off_the_record_browser_context();
+}
+
+AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() {
+ return new ShellAccessTokenStore(browser_context());
+}
+
+ShellBrowserContext*
+ShellContentBrowserClient::ShellBrowserContextForBrowserContext(
+ BrowserContext* content_browser_context) {
+ if (content_browser_context == browser_context())
+ return browser_context();
+ DCHECK_EQ(content_browser_context, off_the_record_browser_context());
+ return off_the_record_browser_context();
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_content_browser_client.h b/content/shell/browser/shell_content_browser_client.h
new file mode 100644
index 0000000..15285ca
--- /dev/null
+++ b/content/shell/browser/shell_content_browser_client.h
@@ -0,0 +1,103 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_
+#define CONTENT_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_
+
+#include <string>
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/platform_file.h"
+#include "content/public/browser/content_browser_client.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+
+namespace content {
+
+class ShellBrowserContext;
+class ShellBrowserMainParts;
+class ShellResourceDispatcherHostDelegate;
+
+class ShellContentBrowserClient : public ContentBrowserClient,
+ public NotificationObserver {
+ public:
+ // Gets the current instance.
+ static ShellContentBrowserClient* Get();
+
+ static void SetSwapProcessesForRedirect(bool swap);
+
+ ShellContentBrowserClient();
+ virtual ~ShellContentBrowserClient();
+
+ // ContentBrowserClient overrides.
+ virtual BrowserMainParts* CreateBrowserMainParts(
+ const MainFunctionParams& parameters) OVERRIDE;
+ virtual void RenderProcessHostCreated(RenderProcessHost* host) OVERRIDE;
+ virtual net::URLRequestContextGetter* CreateRequestContext(
+ BrowserContext* browser_context,
+ ProtocolHandlerMap* protocol_handlers) OVERRIDE;
+ virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition(
+ BrowserContext* browser_context,
+ const base::FilePath& partition_path,
+ bool in_memory,
+ ProtocolHandlerMap* protocol_handlers) OVERRIDE;
+ virtual bool IsHandledURL(const GURL& url) OVERRIDE;
+ virtual void AppendExtraCommandLineSwitches(CommandLine* command_line,
+ int child_process_id) OVERRIDE;
+ virtual void OverrideWebkitPrefs(RenderViewHost* render_view_host,
+ const GURL& url,
+ WebPreferences* prefs) OVERRIDE;
+ virtual void ResourceDispatcherHostCreated() OVERRIDE;
+ virtual AccessTokenStore* CreateAccessTokenStore() OVERRIDE;
+ virtual std::string GetDefaultDownloadName() OVERRIDE;
+ virtual bool SupportsBrowserPlugin(content::BrowserContext* browser_context,
+ const GURL& url) OVERRIDE;
+ virtual WebContentsViewDelegate* GetWebContentsViewDelegate(
+ WebContents* web_contents) OVERRIDE;
+ virtual QuotaPermissionContext* CreateQuotaPermissionContext() OVERRIDE;
+ virtual net::NetLog* GetNetLog() OVERRIDE;
+ virtual bool ShouldSwapProcessesForRedirect(ResourceContext* resource_context,
+ const GURL& current_url,
+ const GURL& new_url) OVERRIDE;
+
+#if defined(OS_ANDROID)
+ virtual void GetAdditionalMappedFilesForChildProcess(
+ const CommandLine& command_line,
+ int child_process_id,
+ std::vector<content::FileDescriptorInfo>* mappings) OVERRIDE;
+#endif
+
+ // NotificationObserver implementation.
+ virtual void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) OVERRIDE;
+
+ ShellBrowserContext* browser_context();
+ ShellBrowserContext* off_the_record_browser_context();
+ ShellResourceDispatcherHostDelegate* resource_dispatcher_host_delegate() {
+ return resource_dispatcher_host_delegate_.get();
+ }
+ ShellBrowserMainParts* shell_browser_main_parts() {
+ return shell_browser_main_parts_;
+ }
+
+ private:
+ ShellBrowserContext* ShellBrowserContextForBrowserContext(
+ BrowserContext* content_browser_context);
+
+ scoped_ptr<ShellResourceDispatcherHostDelegate>
+ resource_dispatcher_host_delegate_;
+
+ base::FilePath webkit_source_dir_;
+
+ ShellBrowserMainParts* shell_browser_main_parts_;
+
+ NotificationRegistrar registrar_;
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_CONTENT_BROWSER_CLIENT_H_
diff --git a/content/shell/browser/shell_devtools_delegate.cc b/content/shell/browser/shell_devtools_delegate.cc
new file mode 100644
index 0000000..0a01405
--- /dev/null
+++ b/content/shell/browser/shell_devtools_delegate.cc
@@ -0,0 +1,119 @@
+// 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_devtools_delegate.h"
+
+#include <vector>
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/strings/string_number_conversions.h"
+#include "content/public/browser/devtools_http_handler.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell.h"
+#include "grit/shell_resources.h"
+#include "net/socket/tcp_listen_socket.h"
+#include "ui/base/resource/resource_bundle.h"
+
+#if defined(OS_ANDROID)
+#include "content/public/browser/android/devtools_auth.h"
+#include "net/socket/unix_domain_socket_posix.h"
+#endif
+
+namespace {
+
+net::StreamListenSocketFactory* CreateSocketFactory() {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+#if defined(OS_ANDROID)
+ std::string socket_name = "content_shell_devtools_remote";
+ if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) {
+ socket_name = command_line.GetSwitchValueASCII(
+ switches::kRemoteDebuggingSocketName);
+ }
+ return new net::UnixDomainSocketWithAbstractNamespaceFactory(
+ socket_name, "", base::Bind(&content::CanUserConnectToDevTools));
+#else
+ // See if the user specified a port on the command line (useful for
+ // automation). If not, use an ephemeral port by specifying 0.
+ int port = 0;
+ if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) {
+ int temp_port;
+ std::string port_str =
+ command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort);
+ if (base::StringToInt(port_str, &temp_port) &&
+ temp_port > 0 && temp_port < 65535) {
+ port = temp_port;
+ } else {
+ DLOG(WARNING) << "Invalid http debugger port number " << temp_port;
+ }
+ }
+ return new net::TCPListenSocketFactory("127.0.0.1", port);
+#endif
+}
+} // namespace
+
+namespace content {
+
+ShellDevToolsDelegate::ShellDevToolsDelegate(BrowserContext* browser_context)
+ : browser_context_(browser_context) {
+ // Note that Content Shell always used bundled DevTools frontend,
+ // even on Android, because the shell is used for running layout tests.
+ devtools_http_handler_ =
+ DevToolsHttpHandler::Start(CreateSocketFactory(), std::string(), this);
+}
+
+ShellDevToolsDelegate::~ShellDevToolsDelegate() {
+}
+
+void ShellDevToolsDelegate::Stop() {
+ // The call below destroys this.
+ devtools_http_handler_->Stop();
+}
+
+std::string ShellDevToolsDelegate::GetDiscoveryPageHTML() {
+ return ResourceBundle::GetSharedInstance().GetRawDataResource(
+ IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE).as_string();
+}
+
+bool ShellDevToolsDelegate::BundlesFrontendResources() {
+ return true;
+}
+
+base::FilePath ShellDevToolsDelegate::GetDebugFrontendDir() {
+ return base::FilePath();
+}
+
+std::string ShellDevToolsDelegate::GetPageThumbnailData(const GURL& url) {
+ return std::string();
+}
+
+RenderViewHost* ShellDevToolsDelegate::CreateNewTarget() {
+ Shell* shell = Shell::CreateNewWindow(browser_context_,
+ GURL(kAboutBlankURL),
+ NULL,
+ MSG_ROUTING_NONE,
+ gfx::Size());
+ return shell->web_contents()->GetRenderViewHost();
+}
+
+DevToolsHttpHandlerDelegate::TargetType
+ShellDevToolsDelegate::GetTargetType(RenderViewHost*) {
+ return kTargetTypeTab;
+}
+
+std::string ShellDevToolsDelegate::GetViewDescription(
+ content::RenderViewHost*) {
+ return std::string();
+}
+
+scoped_refptr<net::StreamListenSocket>
+ShellDevToolsDelegate::CreateSocketForTethering(
+ net::StreamListenSocket::Delegate* delegate,
+ std::string* name) {
+ return NULL;
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_devtools_delegate.h b/content/shell/browser/shell_devtools_delegate.h
new file mode 100644
index 0000000..a218738
--- /dev/null
+++ b/content/shell/browser/shell_devtools_delegate.h
@@ -0,0 +1,50 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "content/public/browser/devtools_http_handler_delegate.h"
+
+namespace content {
+
+class BrowserContext;
+class DevToolsHttpHandler;
+
+class ShellDevToolsDelegate : public DevToolsHttpHandlerDelegate {
+ public:
+ explicit ShellDevToolsDelegate(BrowserContext* browser_context);
+ virtual ~ShellDevToolsDelegate();
+
+ // Stops http server.
+ void Stop();
+
+ // DevToolsHttpProtocolHandler::Delegate overrides.
+ virtual std::string GetDiscoveryPageHTML() OVERRIDE;
+ virtual bool BundlesFrontendResources() OVERRIDE;
+ virtual base::FilePath GetDebugFrontendDir() OVERRIDE;
+ virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE;
+ virtual RenderViewHost* CreateNewTarget() OVERRIDE;
+ virtual TargetType GetTargetType(RenderViewHost*) OVERRIDE;
+ virtual std::string GetViewDescription(content::RenderViewHost*) OVERRIDE;
+ virtual scoped_refptr<net::StreamListenSocket> CreateSocketForTethering(
+ net::StreamListenSocket::Delegate* delegate,
+ std::string* name) OVERRIDE;
+
+ DevToolsHttpHandler* devtools_http_handler() {
+ return devtools_http_handler_;
+ }
+
+ private:
+ BrowserContext* browser_context_;
+ DevToolsHttpHandler* devtools_http_handler_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellDevToolsDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_DELEGATE_H_
diff --git a/content/shell/browser/shell_devtools_frontend.cc b/content/shell/browser/shell_devtools_frontend.cc
new file mode 100644
index 0000000..8c3f74b
--- /dev/null
+++ b/content/shell/browser/shell_devtools_frontend.cc
@@ -0,0 +1,107 @@
+// 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_devtools_frontend.h"
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "content/public/browser/devtools_http_handler.h"
+#include "content/public/browser/devtools_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/content_client.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.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_delegate.h"
+#include "content/shell/common/shell_switches.h"
+#include "net/base/net_util.h"
+
+namespace content {
+
+namespace {
+
+// DevTools frontend path for inspector LayoutTests.
+GURL GetDevToolsPathAsURL() {
+ base::FilePath dir_exe;
+ if (!PathService::Get(base::DIR_EXE, &dir_exe)) {
+ NOTREACHED();
+ return GURL();
+ }
+#if defined(OS_MACOSX)
+ // On Mac, the executable is in
+ // out/Release/Content Shell.app/Contents/MacOS/Content Shell.
+ // We need to go up 3 directories to get to out/Release.
+ dir_exe = dir_exe.AppendASCII("../../..");
+#endif
+ base::FilePath dev_tools_path = dir_exe.AppendASCII(
+ "resources/inspector/devtools.html");
+ return net::FilePathToFileURL(dev_tools_path);
+}
+
+} // namespace
+
+// static
+ShellDevToolsFrontend* ShellDevToolsFrontend::Show(
+ WebContents* inspected_contents) {
+ Shell* shell = Shell::CreateNewWindow(inspected_contents->GetBrowserContext(),
+ GURL(),
+ NULL,
+ MSG_ROUTING_NONE,
+ gfx::Size());
+ ShellDevToolsFrontend* devtools_frontend = new ShellDevToolsFrontend(
+ shell,
+ DevToolsAgentHost::GetOrCreateFor(inspected_contents->GetRenderViewHost())
+ .get());
+
+ ShellDevToolsDelegate* delegate = ShellContentBrowserClient::Get()->
+ shell_browser_main_parts()->devtools_delegate();
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ shell->LoadURL(GetDevToolsPathAsURL());
+ else
+ shell->LoadURL(delegate->devtools_http_handler()->GetFrontendURL(NULL));
+
+ return devtools_frontend;
+}
+
+void ShellDevToolsFrontend::Focus() {
+ web_contents()->GetView()->Focus();
+}
+
+void ShellDevToolsFrontend::Close() {
+ frontend_shell_->Close();
+}
+
+ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell,
+ DevToolsAgentHost* agent_host)
+ : WebContentsObserver(frontend_shell->web_contents()),
+ frontend_shell_(frontend_shell),
+ agent_host_(agent_host) {
+ frontend_host_.reset(
+ DevToolsClientHost::CreateDevToolsFrontendHost(web_contents(), this));
+}
+
+ShellDevToolsFrontend::~ShellDevToolsFrontend() {
+}
+
+void ShellDevToolsFrontend::RenderViewCreated(
+ RenderViewHost* render_view_host) {
+ DevToolsClientHost::SetupDevToolsFrontendClient(
+ web_contents()->GetRenderViewHost());
+ DevToolsManager* manager = DevToolsManager::GetInstance();
+ manager->RegisterDevToolsClientHostFor(agent_host_.get(),
+ frontend_host_.get());
+}
+
+void ShellDevToolsFrontend::WebContentsDestroyed(WebContents* web_contents) {
+ DevToolsManager::GetInstance()->ClientHostClosing(frontend_host_.get());
+ delete this;
+}
+
+void ShellDevToolsFrontend::InspectedContentsClosing() {
+ frontend_shell_->Close();
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_devtools_frontend.h b/content/shell/browser/shell_devtools_frontend.h
new file mode 100644
index 0000000..b6a617f
--- /dev/null
+++ b/content/shell/browser/shell_devtools_frontend.h
@@ -0,0 +1,73 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_FRONTEND_H_
+#define CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_FRONTEND_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/devtools_agent_host.h"
+#include "content/public/browser/devtools_client_host.h"
+#include "content/public/browser/devtools_frontend_host_delegate.h"
+#include "content/public/browser/web_contents_observer.h"
+
+namespace content {
+
+class RenderViewHost;
+class Shell;
+class WebContents;
+
+class ShellDevToolsFrontend : public WebContentsObserver,
+ public DevToolsFrontendHostDelegate {
+ public:
+ static ShellDevToolsFrontend* Show(WebContents* inspected_contents);
+ void Focus();
+ void Close();
+
+ Shell* frontend_shell() const { return frontend_shell_; }
+
+ private:
+ ShellDevToolsFrontend(Shell* frontend_shell, DevToolsAgentHost* agent_host);
+ virtual ~ShellDevToolsFrontend();
+
+ // WebContentsObserver overrides
+ virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
+ virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
+
+ // DevToolsFrontendHostDelegate implementation
+ virtual void ActivateWindow() OVERRIDE {}
+ virtual void ChangeAttachedWindowHeight(unsigned height) OVERRIDE {}
+ virtual void CloseWindow() OVERRIDE {}
+ virtual void MoveWindow(int x, int y) OVERRIDE {}
+ virtual void SetDockSide(const std::string& side) OVERRIDE {}
+ virtual void OpenInNewTab(const std::string& url) OVERRIDE {}
+ virtual void SaveToFile(const std::string& url,
+ const std::string& content,
+ bool save_as) OVERRIDE {}
+ virtual void AppendToFile(const std::string& url,
+ const std::string& content) OVERRIDE {}
+ virtual void RequestFileSystems() OVERRIDE {}
+ virtual void AddFileSystem() OVERRIDE {}
+ virtual void RemoveFileSystem(const std::string& file_system_path) OVERRIDE {}
+ virtual void IndexPath(int request_id,
+ const std::string& file_system_path) OVERRIDE {}
+ virtual void StopIndexing(int request_id) OVERRIDE {}
+ virtual void SearchInPath(int request_id,
+ const std::string& file_system_path,
+ const std::string& query) OVERRIDE {}
+
+ virtual void InspectedContentsClosing() OVERRIDE;
+
+ Shell* frontend_shell_;
+ scoped_refptr<DevToolsAgentHost> agent_host_;
+ scoped_ptr<DevToolsClientHost> frontend_host_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellDevToolsFrontend);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_FRONTEND_H_
diff --git a/content/shell/browser/shell_download_manager_delegate.cc b/content/shell/browser/shell_download_manager_delegate.cc
new file mode 100644
index 0000000..1dbbea7
--- /dev/null
+++ b/content/shell/browser/shell_download_manager_delegate.cc
@@ -0,0 +1,211 @@
+// 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_download_manager_delegate.h"
+
+#if defined(TOOLKIT_GTK)
+#include <gtk/gtk.h>
+#endif
+
+#if defined(OS_WIN)
+#include <windows.h>
+#include <commdlg.h>
+#endif
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/file_util.h"
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/download_manager.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_switches.h"
+#include "net/base/net_util.h"
+
+namespace content {
+
+ShellDownloadManagerDelegate::ShellDownloadManagerDelegate()
+ : download_manager_(NULL),
+ suppress_prompting_(false) {
+ // Balanced in Shutdown();
+ AddRef();
+}
+
+ShellDownloadManagerDelegate::~ShellDownloadManagerDelegate(){
+}
+
+
+void ShellDownloadManagerDelegate::SetDownloadManager(
+ DownloadManager* download_manager) {
+ download_manager_ = download_manager;
+}
+
+void ShellDownloadManagerDelegate::Shutdown() {
+ Release();
+}
+
+bool ShellDownloadManagerDelegate::DetermineDownloadTarget(
+ DownloadItem* download,
+ const DownloadTargetCallback& callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // This assignment needs to be here because even at the call to
+ // SetDownloadManager, the system is not fully initialized.
+ if (default_download_path_.empty()) {
+ default_download_path_ = download_manager_->GetBrowserContext()->GetPath().
+ Append(FILE_PATH_LITERAL("Downloads"));
+ }
+
+ if (!download->GetForcedFilePath().empty()) {
+ callback.Run(download->GetForcedFilePath(),
+ DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ download->GetForcedFilePath());
+ return true;
+ }
+
+ base::FilePath generated_name = net::GenerateFileName(
+ download->GetURL(),
+ download->GetContentDisposition(),
+ EmptyString(),
+ download->GetSuggestedFilename(),
+ download->GetMimeType(),
+ "download");
+
+ BrowserThread::PostTask(
+ BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(
+ &ShellDownloadManagerDelegate::GenerateFilename,
+ this, download->GetId(), callback, generated_name,
+ default_download_path_));
+ return true;
+}
+
+bool ShellDownloadManagerDelegate::ShouldOpenDownload(
+ DownloadItem* item,
+ const DownloadOpenDelayedCallback& callback) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree) &&
+ WebKitTestController::Get()->IsMainWindow(item->GetWebContents()) &&
+ item->GetMimeType() == "text/html") {
+ WebKitTestController::Get()->OpenURL(
+ net::FilePathToFileURL(item->GetFullPath()));
+ }
+ return true;
+}
+
+void ShellDownloadManagerDelegate::GetNextId(
+ const DownloadIdCallback& callback) {
+ static uint32 next_id = DownloadItem::kInvalidId + 1;
+ callback.Run(next_id++);
+}
+
+void ShellDownloadManagerDelegate::GenerateFilename(
+ uint32 download_id,
+ const DownloadTargetCallback& callback,
+ const base::FilePath& generated_name,
+ const base::FilePath& suggested_directory) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ if (!base::PathExists(suggested_directory))
+ file_util::CreateDirectory(suggested_directory);
+
+ base::FilePath suggested_path(suggested_directory.Append(generated_name));
+ BrowserThread::PostTask(
+ BrowserThread::UI,
+ FROM_HERE,
+ base::Bind(
+ &ShellDownloadManagerDelegate::OnDownloadPathGenerated,
+ this, download_id, callback, suggested_path));
+}
+
+void ShellDownloadManagerDelegate::OnDownloadPathGenerated(
+ uint32 download_id,
+ const DownloadTargetCallback& callback,
+ const base::FilePath& suggested_path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ if (suppress_prompting_) {
+ // Testing exit.
+ callback.Run(suggested_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
+ suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload")));
+ return;
+ }
+
+ ChooseDownloadPath(download_id, callback, suggested_path);
+}
+
+void ShellDownloadManagerDelegate::ChooseDownloadPath(
+ uint32 download_id,
+ const DownloadTargetCallback& callback,
+ const base::FilePath& suggested_path) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ DownloadItem* item = download_manager_->GetDownload(download_id);
+ if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
+ return;
+
+ base::FilePath result;
+#if defined(OS_WIN) && !defined(USE_AURA)
+ std::wstring file_part = base::FilePath(suggested_path).BaseName().value();
+ wchar_t file_name[MAX_PATH];
+ base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
+ OPENFILENAME save_as;
+ ZeroMemory(&save_as, sizeof(save_as));
+ save_as.lStructSize = sizeof(OPENFILENAME);
+ save_as.hwndOwner = item->GetWebContents()->GetView()->GetNativeView();
+ save_as.lpstrFile = file_name;
+ save_as.nMaxFile = arraysize(file_name);
+
+ std::wstring directory;
+ if (!suggested_path.empty())
+ directory = suggested_path.DirName().value();
+
+ save_as.lpstrInitialDir = directory.c_str();
+ save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
+ OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;
+
+ if (GetSaveFileName(&save_as))
+ result = base::FilePath(std::wstring(save_as.lpstrFile));
+#elif defined(TOOLKIT_GTK)
+ GtkWidget *dialog;
+ gfx::NativeWindow parent_window;
+ std::string base_name = base::FilePath(suggested_path).BaseName().value();
+
+ parent_window = item->GetWebContents()->GetView()->GetTopLevelNativeWindow();
+ dialog = gtk_file_chooser_dialog_new("Save File",
+ parent_window,
+ GTK_FILE_CHOOSER_ACTION_SAVE,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
+ TRUE);
+ gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
+ base_name.c_str());
+
+ if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
+ char *filename;
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
+ result = base::FilePath(filename);
+ g_free(filename);
+ }
+ gtk_widget_destroy(dialog);
+#else
+ NOTIMPLEMENTED();
+#endif
+
+ callback.Run(result, DownloadItem::TARGET_DISPOSITION_PROMPT,
+ DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, result);
+}
+
+void ShellDownloadManagerDelegate::SetDownloadBehaviorForTesting(
+ const base::FilePath& default_download_path) {
+ default_download_path_ = default_download_path;
+ suppress_prompting_ = true;
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_download_manager_delegate.h b/content/shell/browser/shell_download_manager_delegate.h
new file mode 100644
index 0000000..afd57e7
--- /dev/null
+++ b/content/shell/browser/shell_download_manager_delegate.h
@@ -0,0 +1,65 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/ref_counted.h"
+#include "content/public/browser/download_manager_delegate.h"
+
+namespace content {
+
+class DownloadManager;
+
+class ShellDownloadManagerDelegate
+ : public DownloadManagerDelegate,
+ public base::RefCountedThreadSafe<ShellDownloadManagerDelegate> {
+ public:
+ ShellDownloadManagerDelegate();
+
+ void SetDownloadManager(DownloadManager* manager);
+
+ virtual void Shutdown() OVERRIDE;
+ virtual bool DetermineDownloadTarget(
+ DownloadItem* download,
+ const DownloadTargetCallback& callback) OVERRIDE;
+ virtual bool ShouldOpenDownload(
+ DownloadItem* item,
+ const DownloadOpenDelayedCallback& callback) OVERRIDE;
+ virtual void GetNextId(const DownloadIdCallback& callback) OVERRIDE;
+
+ // Inhibits prompting and sets the default download path.
+ void SetDownloadBehaviorForTesting(
+ const base::FilePath& default_download_path);
+
+ protected:
+ // To allow subclasses for testing.
+ virtual ~ShellDownloadManagerDelegate();
+
+ private:
+ friend class base::RefCountedThreadSafe<ShellDownloadManagerDelegate>;
+
+
+ void GenerateFilename(uint32 download_id,
+ const DownloadTargetCallback& callback,
+ const base::FilePath& generated_name,
+ const base::FilePath& suggested_directory);
+ void OnDownloadPathGenerated(uint32 download_id,
+ const DownloadTargetCallback& callback,
+ const base::FilePath& suggested_path);
+ void ChooseDownloadPath(uint32 download_id,
+ const DownloadTargetCallback& callback,
+ const base::FilePath& suggested_path);
+
+ DownloadManager* download_manager_;
+ base::FilePath default_download_path_;
+ bool suppress_prompting_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellDownloadManagerDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
diff --git a/content/shell/browser/shell_gtk.cc b/content/shell/browser/shell_gtk.cc
new file mode 100644
index 0000000..a06a6a0
--- /dev/null
+++ b/content/shell/browser/shell_gtk.cc
@@ -0,0 +1,339 @@
+// 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 <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/renderer_preferences.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+
+namespace content {
+
+namespace {
+
+// Callback for Debug > Show web inspector... menu item.
+gboolean ShowWebInspectorActivated(GtkWidget* widget, Shell* shell) {
+ shell->ShowDevTools();
+ return FALSE; // Don't stop this message.
+}
+
+GtkWidget* AddMenuEntry(GtkWidget* menu_widget, const char* text,
+ GCallback callback, Shell* shell) {
+ GtkWidget* entry = gtk_menu_item_new_with_label(text);
+ g_signal_connect(entry, "activate", callback, shell);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_widget), entry);
+ return entry;
+}
+
+GtkWidget* CreateMenu(GtkWidget* menu_bar, const char* text) {
+ GtkWidget* menu_widget = gtk_menu_new();
+ GtkWidget* menu_header = gtk_menu_item_new_with_label(text);
+ gtk_menu_item_set_submenu(GTK_MENU_ITEM(menu_header), menu_widget);
+ gtk_menu_shell_append(GTK_MENU_SHELL(menu_bar), menu_header);
+ return menu_widget;
+}
+
+GtkWidget* CreateMenuBar(Shell* shell) {
+ GtkWidget* menu_bar = gtk_menu_bar_new();
+ GtkWidget* debug_menu = CreateMenu(menu_bar, "Debug");
+ AddMenuEntry(debug_menu, "Show web inspector...",
+ G_CALLBACK(ShowWebInspectorActivated), shell);
+ return menu_bar;
+}
+
+} // namespace
+
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+}
+
+void Shell::PlatformCleanUp() {
+ // Nothing to clean up; GTK will clean up the widgets shortly after.
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+ if (headless_)
+ return;
+
+ GtkToolItem* item = NULL;
+ switch (control) {
+ case BACK_BUTTON:
+ item = back_button_;
+ break;
+ case FORWARD_BUTTON:
+ item = forward_button_;
+ break;
+ case STOP_BUTTON:
+ item = stop_button_;
+ break;
+ default:
+ NOTREACHED() << "Unknown UI control";
+ return;
+ }
+ gtk_widget_set_sensitive(GTK_WIDGET(item), is_enabled);
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+ if (headless_)
+ return;
+
+ gtk_entry_set_text(GTK_ENTRY(url_edit_view_), url.spec().c_str());
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+ if (headless_)
+ return;
+
+ if (loading)
+ gtk_spinner_start(GTK_SPINNER(spinner_));
+ else
+ gtk_spinner_stop(GTK_SPINNER(spinner_));
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+ ui_elements_height_ = 0;
+ if (headless_) {
+ SizeTo(width, height);
+ return;
+ }
+
+ window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL));
+ gtk_window_set_title(window_, "Content Shell");
+ g_signal_connect(G_OBJECT(window_), "destroy",
+ G_CALLBACK(OnWindowDestroyedThunk), this);
+
+ vbox_ = gtk_vbox_new(FALSE, 0);
+
+ // Create the menu bar.
+ GtkWidget* menu_bar = CreateMenuBar(this);
+ gtk_box_pack_start(GTK_BOX(vbox_), menu_bar, FALSE, FALSE, 0);
+
+ // Create the object that mediates accelerators.
+ GtkAccelGroup* accel_group = gtk_accel_group_new();
+ gtk_window_add_accel_group(GTK_WINDOW(window_), accel_group);
+
+ // Set global window handling accelerators:
+ gtk_accel_group_connect(
+ accel_group, GDK_w, GDK_CONTROL_MASK,
+ GTK_ACCEL_VISIBLE,
+ g_cclosure_new(G_CALLBACK(OnCloseWindowKeyPressedThunk),
+ this, NULL));
+
+ gtk_accel_group_connect(
+ accel_group, GDK_n, GDK_CONTROL_MASK,
+ GTK_ACCEL_VISIBLE,
+ g_cclosure_new(G_CALLBACK(OnNewWindowKeyPressedThunk),
+ this, NULL));
+
+ gtk_accel_group_connect(
+ accel_group, GDK_F5, (GdkModifierType)0,
+ GTK_ACCEL_VISIBLE,
+ g_cclosure_new(G_CALLBACK(OnReloadKeyPressedThunk),
+ this, NULL));
+
+ GtkWidget* toolbar = gtk_toolbar_new();
+ // Turn off the labels on the toolbar buttons.
+ gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
+
+ back_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
+ g_signal_connect(back_button_, "clicked",
+ G_CALLBACK(&OnBackButtonClickedThunk), this);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), back_button_, -1 /* append */);
+ gtk_widget_add_accelerator(GTK_WIDGET(back_button_), "clicked", accel_group,
+ GDK_Left, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
+
+ forward_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
+ g_signal_connect(forward_button_, "clicked",
+ G_CALLBACK(&OnForwardButtonClickedThunk), this);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), forward_button_, -1 /* append */);
+ gtk_widget_add_accelerator(GTK_WIDGET(forward_button_), "clicked",
+ accel_group,
+ GDK_Right, GDK_MOD1_MASK, GTK_ACCEL_VISIBLE);
+
+ reload_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_REFRESH);
+ g_signal_connect(reload_button_, "clicked",
+ G_CALLBACK(&OnReloadButtonClickedThunk), this);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), reload_button_, -1 /* append */);
+ gtk_widget_add_accelerator(GTK_WIDGET(reload_button_), "clicked",
+ accel_group,
+ GDK_r, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
+
+ stop_button_ = gtk_tool_button_new_from_stock(GTK_STOCK_STOP);
+ g_signal_connect(stop_button_, "clicked",
+ G_CALLBACK(&OnStopButtonClickedThunk), this);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), stop_button_, -1 /* append */);
+
+ url_edit_view_ = gtk_entry_new();
+ g_signal_connect(G_OBJECT(url_edit_view_), "activate",
+ G_CALLBACK(&OnURLEntryActivateThunk), this);
+
+ gtk_accel_group_connect(
+ accel_group, GDK_l, GDK_CONTROL_MASK,
+ GTK_ACCEL_VISIBLE,
+ g_cclosure_new(G_CALLBACK(OnHighlightURLViewThunk),
+ this, NULL));
+
+ GtkToolItem* tool_item = gtk_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(tool_item), url_edit_view_);
+ gtk_tool_item_set_expand(tool_item, TRUE);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), tool_item, -1 /* append */);
+
+ // Center a 20x20 spinner in a 26x24 area.
+ GtkWidget* spinner_alignment = gtk_alignment_new(0.5, 0.5, 0, 0);
+ gtk_alignment_set_padding(GTK_ALIGNMENT(spinner_alignment), 2, 2, 4, 4);
+ spinner_ = gtk_spinner_new();
+ gtk_widget_set_size_request(spinner_, 20, 20);
+ gtk_container_add(GTK_CONTAINER(spinner_alignment), spinner_);
+
+ spinner_item_ = gtk_tool_item_new();
+ gtk_container_add(GTK_CONTAINER(spinner_item_), spinner_alignment);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), spinner_item_, -1 /* append */);
+
+ gtk_box_pack_start(GTK_BOX(vbox_), toolbar, FALSE, FALSE, 0);
+
+ gtk_container_add(GTK_CONTAINER(window_), vbox_);
+
+ // Trigger layout of the UI elements, so that we can measure their
+ // heights. The width and height passed to this method are meant for the web
+ // contents view, not the top-level window. Since Gtk only seems to provide a
+ // suitable resizing function for top-level windows, we need to know how to
+ // convert from web contents view size to top-level window size.
+ gtk_widget_show_all(GTK_WIDGET(vbox_));
+
+ // Measure the heights of the UI elements, now that they have been laid out.
+ GtkRequisition elm_size;
+ gtk_widget_size_request(menu_bar, &elm_size);
+ ui_elements_height_ += elm_size.height;
+ gtk_widget_size_request(toolbar, &elm_size);
+ ui_elements_height_ += elm_size.height;
+
+ // We're ready to set an initial window size.
+ SizeTo(width, height);
+
+ // Finally, show the window.
+ gtk_widget_show_all(GTK_WIDGET(window_));
+}
+
+void Shell::PlatformSetContents() {
+ if (headless_)
+ return;
+
+ WebContentsView* content_view = web_contents_->GetView();
+ gtk_container_add(GTK_CONTAINER(vbox_), content_view->GetNativeView());
+}
+
+void Shell::SizeTo(int width, int height) {
+ content_width_ = width;
+ content_height_ = height;
+
+ // Prefer setting the top level window's size (if we have one), rather than
+ // setting the inner widget's minimum size (so that the user can shrink the
+ // window if she wants).
+ if (window_) {
+ gtk_window_resize(window_, width, height + ui_elements_height_);
+ } else if (web_contents_) {
+ gtk_widget_set_size_request(web_contents_->GetView()->GetNativeView(),
+ width, height);
+ }
+}
+
+void Shell::PlatformResizeSubViews() {
+ SizeTo(content_width_, content_height_);
+}
+
+void Shell::Close() {
+ if (headless_) {
+ delete this;
+ return;
+ }
+
+ gtk_widget_destroy(GTK_WIDGET(window_));
+}
+
+void Shell::OnBackButtonClicked(GtkWidget* widget) {
+ GoBackOrForward(-1);
+}
+
+void Shell::OnForwardButtonClicked(GtkWidget* widget) {
+ GoBackOrForward(1);
+}
+
+void Shell::OnReloadButtonClicked(GtkWidget* widget) {
+ Reload();
+}
+
+void Shell::OnStopButtonClicked(GtkWidget* widget) {
+ Stop();
+}
+
+void Shell::OnURLEntryActivate(GtkWidget* entry) {
+ const gchar* str = gtk_entry_get_text(GTK_ENTRY(entry));
+ GURL url(str);
+ if (!url.has_scheme())
+ url = GURL(std::string("http://") + std::string(str));
+ LoadURL(GURL(url));
+}
+
+// Callback for when the main window is destroyed.
+gboolean Shell::OnWindowDestroyed(GtkWidget* window) {
+ delete this;
+ return FALSE; // Don't stop this message.
+}
+
+gboolean Shell::OnCloseWindowKeyPressed(GtkAccelGroup* accel_group,
+ GObject* acceleratable,
+ guint keyval,
+ GdkModifierType modifier) {
+ gtk_widget_destroy(GTK_WIDGET(window_));
+ return TRUE;
+}
+
+gboolean Shell::OnNewWindowKeyPressed(GtkAccelGroup* accel_group,
+ GObject* acceleratable,
+ guint keyval,
+ GdkModifierType modifier) {
+ ShellBrowserContext* browser_context =
+ ShellContentBrowserClient::Get()->browser_context();
+ Shell::CreateNewWindow(browser_context,
+ GURL(),
+ NULL,
+ MSG_ROUTING_NONE,
+ gfx::Size());
+ return TRUE;
+}
+
+gboolean Shell::OnHighlightURLView(GtkAccelGroup* accel_group,
+ GObject* acceleratable,
+ guint keyval,
+ GdkModifierType modifier) {
+ gtk_widget_grab_focus(GTK_WIDGET(url_edit_view_));
+ return TRUE;
+}
+
+gboolean Shell::OnReloadKeyPressed(GtkAccelGroup* accel_group,
+ GObject* acceleratable,
+ guint keyval,
+ GdkModifierType modifier) {
+ Reload();
+ return TRUE;
+}
+
+void Shell::PlatformSetTitle(const string16& title) {
+ if (headless_)
+ return;
+
+ std::string title_utf8 = UTF16ToUTF8(title);
+ gtk_window_set_title(GTK_WINDOW(window_), title_utf8.c_str());
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_javascript_dialog.h b/content/shell/browser/shell_javascript_dialog.h
new file mode 100644
index 0000000..4001334
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog.h
@@ -0,0 +1,64 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_H_
+#define CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_H_
+
+#include "content/public/browser/javascript_dialog_manager.h"
+
+#if defined(TOOLKIT_GTK)
+#include "ui/base/gtk/gtk_signal.h"
+#endif
+
+#if defined(OS_MACOSX)
+#if __OBJC__
+@class ShellJavaScriptDialogHelper;
+#else
+class ShellJavaScriptDialogHelper;
+#endif // __OBJC__
+#endif // defined(OS_MACOSX)
+
+namespace content {
+
+class ShellJavaScriptDialogManager;
+
+class ShellJavaScriptDialog {
+ public:
+ ShellJavaScriptDialog(
+ ShellJavaScriptDialogManager* manager,
+ gfx::NativeWindow parent_window,
+ JavaScriptMessageType message_type,
+ const string16& message_text,
+ const string16& default_prompt_text,
+ const JavaScriptDialogManager::DialogClosedCallback& callback);
+ ~ShellJavaScriptDialog();
+
+ // Called to cancel a dialog mid-flight.
+ void Cancel();
+
+ private:
+ ShellJavaScriptDialogManager* manager_;
+ JavaScriptDialogManager::DialogClosedCallback callback_;
+
+#if defined(OS_MACOSX)
+ ShellJavaScriptDialogHelper* helper_; // owned
+#elif defined(OS_WIN)
+ JavaScriptMessageType message_type_;
+ HWND dialog_win_;
+ string16 message_text_;
+ string16 default_prompt_text_;
+ static INT_PTR CALLBACK DialogProc(HWND dialog, UINT message, WPARAM wparam,
+ LPARAM lparam);
+#elif defined(TOOLKIT_GTK)
+ GtkWidget* gtk_dialog_;
+ gfx::NativeWindow parent_window_;
+ CHROMEGTK_CALLBACK_1(ShellJavaScriptDialog, void, OnResponse, int);
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ShellJavaScriptDialog);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_H_
diff --git a/content/shell/browser/shell_javascript_dialog_gtk.cc b/content/shell/browser/shell_javascript_dialog_gtk.cc
new file mode 100644
index 0000000..87bd6f3
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_gtk.cc
@@ -0,0 +1,127 @@
+// 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_javascript_dialog.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "base/strings/string_util.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/shell/app/resource.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
+
+namespace {
+
+const char kPromptTextId[] = "content_shell_prompt_text";
+
+// If there's a text entry in the dialog, get the text from the first one and
+// return it.
+string16 GetPromptText(GtkDialog* dialog) {
+ GtkWidget* widget = static_cast<GtkWidget*>(
+ g_object_get_data(G_OBJECT(dialog), kPromptTextId));
+ if (widget)
+ return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(widget)));
+ return string16();
+}
+
+} // namespace
+
+
+namespace content {
+
+ShellJavaScriptDialog::ShellJavaScriptDialog(
+ ShellJavaScriptDialogManager* manager,
+ gfx::NativeWindow parent_window,
+ JavaScriptMessageType message_type,
+ const string16& message_text,
+ const string16& default_prompt_text,
+ const JavaScriptDialogManager::DialogClosedCallback& callback)
+ : manager_(manager),
+ callback_(callback),
+ parent_window_(parent_window) {
+ GtkButtonsType buttons = GTK_BUTTONS_NONE;
+ GtkMessageType gtk_message_type = GTK_MESSAGE_OTHER;
+
+ switch (message_type) {
+ case content::JAVASCRIPT_MESSAGE_TYPE_ALERT:
+ buttons = GTK_BUTTONS_NONE;
+ gtk_message_type = GTK_MESSAGE_WARNING;
+ break;
+
+ case content::JAVASCRIPT_MESSAGE_TYPE_CONFIRM:
+ buttons = GTK_BUTTONS_CANCEL;
+ gtk_message_type = GTK_MESSAGE_QUESTION;
+ break;
+
+ case content::JAVASCRIPT_MESSAGE_TYPE_PROMPT:
+ buttons = GTK_BUTTONS_CANCEL;
+ gtk_message_type = GTK_MESSAGE_QUESTION;
+ break;
+
+ default:
+ NOTREACHED();
+ }
+
+ gtk_dialog_ = gtk_message_dialog_new(parent_window_,
+ GTK_DIALOG_MODAL,
+ gtk_message_type,
+ buttons,
+ "%s",
+ UTF16ToUTF8(message_text).c_str());
+ g_signal_connect(gtk_dialog_,
+ "delete-event",
+ G_CALLBACK(gtk_widget_hide_on_delete),
+ NULL);
+ gtk_window_set_title(GTK_WINDOW(gtk_dialog_), "JavaScript");
+
+ GtkWidget* ok_button = gtk_dialog_add_button(GTK_DIALOG(gtk_dialog_),
+ GTK_STOCK_OK,
+ GTK_RESPONSE_OK);
+
+ if (message_type != content::JAVASCRIPT_MESSAGE_TYPE_PROMPT)
+ gtk_widget_grab_focus(ok_button);
+
+ if (message_type == content::JAVASCRIPT_MESSAGE_TYPE_PROMPT) {
+ GtkWidget* content_area =
+ gtk_dialog_get_content_area(GTK_DIALOG(gtk_dialog_));
+ GtkWidget* text_box = gtk_entry_new();
+ gtk_entry_set_text(GTK_ENTRY(text_box),
+ UTF16ToUTF8(default_prompt_text).c_str());
+ gtk_box_pack_start(GTK_BOX(content_area), text_box, TRUE, TRUE, 0);
+ g_object_set_data(G_OBJECT(gtk_dialog_), kPromptTextId, text_box);
+ gtk_entry_set_activates_default(GTK_ENTRY(text_box), TRUE);
+ }
+
+ gtk_dialog_set_default_response(GTK_DIALOG(gtk_dialog_), GTK_RESPONSE_OK);
+ g_signal_connect(gtk_dialog_, "response", G_CALLBACK(OnResponseThunk), this);
+ gtk_widget_show_all(GTK_WIDGET(gtk_dialog_));
+}
+
+ShellJavaScriptDialog::~ShellJavaScriptDialog() {
+}
+
+void ShellJavaScriptDialog::Cancel() {
+}
+
+void ShellJavaScriptDialog::OnResponse(GtkWidget* dialog, int response_id) {
+ switch (response_id) {
+ case GTK_RESPONSE_OK:
+ callback_.Run(true, GetPromptText(GTK_DIALOG(dialog)));
+ break;
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
+ callback_.Run(false, string16());
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ gtk_widget_destroy(dialog);
+
+ manager_->DialogClosed(this);
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_javascript_dialog_mac.mm b/content/shell/browser/shell_javascript_dialog_mac.mm
new file mode 100644
index 0000000..fe9de98
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_mac.mm
@@ -0,0 +1,138 @@
+// 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_javascript_dialog.h"
+
+#import <Cocoa/Cocoa.h>
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
+
+// Helper object that receives the notification that the dialog/sheet is
+// going away. Is responsible for cleaning itself up.
+@interface ShellJavaScriptDialogHelper : NSObject<NSAlertDelegate> {
+ @private
+ base::scoped_nsobject<NSAlert> alert_;
+ NSTextField* textField_; // WEAK; owned by alert_
+
+ // Copies of the fields in ShellJavaScriptDialog because they're private.
+ content::ShellJavaScriptDialogManager* manager_;
+ content::JavaScriptDialogManager::DialogClosedCallback callback_;
+}
+
+- (id)initHelperWithManager:(content::ShellJavaScriptDialogManager*)manager
+ andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback;
+- (NSAlert*)alert;
+- (NSTextField*)textField;
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+- (void)cancel;
+
+@end
+
+@implementation ShellJavaScriptDialogHelper
+
+- (id)initHelperWithManager:(content::ShellJavaScriptDialogManager*)manager
+ andCallback:(content::JavaScriptDialogManager::DialogClosedCallback)callback {
+ if (self = [super init]) {
+ manager_ = manager;
+ callback_ = callback;
+ }
+
+ return self;
+}
+
+- (NSAlert*)alert {
+ alert_.reset([[NSAlert alloc] init]);
+ return alert_;
+}
+
+- (NSTextField*)textField {
+ textField_ = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 300, 22)];
+ [[textField_ cell] setLineBreakMode:NSLineBreakByTruncatingTail];
+ [alert_ setAccessoryView:textField_];
+ [textField_ release];
+
+ return textField_;
+}
+
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ if (returnCode == NSRunStoppedResponse)
+ return;
+
+ bool success = returnCode == NSAlertFirstButtonReturn;
+ string16 input;
+ if (textField_)
+ input = base::SysNSStringToUTF16([textField_ stringValue]);
+
+ content::ShellJavaScriptDialog* native_dialog =
+ reinterpret_cast<content::ShellJavaScriptDialog*>(contextInfo);
+ callback_.Run(success, input);
+ manager_->DialogClosed(native_dialog);
+}
+
+- (void)cancel {
+ [NSApp endSheet:[alert_ window]];
+ alert_.reset();
+}
+
+@end
+
+namespace content {
+
+ShellJavaScriptDialog::ShellJavaScriptDialog(
+ ShellJavaScriptDialogManager* manager,
+ gfx::NativeWindow parent_window,
+ JavaScriptMessageType message_type,
+ const string16& message_text,
+ const string16& default_prompt_text,
+ const JavaScriptDialogManager::DialogClosedCallback& callback)
+ : manager_(manager),
+ callback_(callback) {
+ bool text_field = message_type == JAVASCRIPT_MESSAGE_TYPE_PROMPT;
+ bool one_button = message_type == JAVASCRIPT_MESSAGE_TYPE_ALERT;
+
+ helper_ =
+ [[ShellJavaScriptDialogHelper alloc] initHelperWithManager:manager
+ andCallback:callback];
+
+ // Show the modal dialog.
+ NSAlert* alert = [helper_ alert];
+ NSTextField* field = nil;
+ if (text_field) {
+ field = [helper_ textField];
+ [field setStringValue:base::SysUTF16ToNSString(default_prompt_text)];
+ }
+ [alert setDelegate:helper_];
+ [alert setInformativeText:base::SysUTF16ToNSString(message_text)];
+ [alert setMessageText:@"Javascript alert"];
+ [alert addButtonWithTitle:@"OK"];
+ if (!one_button) {
+ NSButton* other = [alert addButtonWithTitle:@"Cancel"];
+ [other setKeyEquivalent:@"\e"];
+ }
+
+ [alert
+ beginSheetModalForWindow:nil // nil here makes it app-modal
+ modalDelegate:helper_
+ didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+ contextInfo:this];
+
+ if ([alert accessoryView])
+ [[alert window] makeFirstResponder:[alert accessoryView]];
+}
+
+ShellJavaScriptDialog::~ShellJavaScriptDialog() {
+ [helper_ release];
+}
+
+void ShellJavaScriptDialog::Cancel() {
+ [helper_ cancel];
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_javascript_dialog_manager.cc b/content/shell/browser/shell_javascript_dialog_manager.cc
new file mode 100644
index 0000000..1476f7c
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_manager.cc
@@ -0,0 +1,143 @@
+// 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_javascript_dialog_manager.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/shell/browser/shell_javascript_dialog.h"
+#include "content/shell/browser/webkit_test_controller.h"
+#include "content/shell/common/shell_switches.h"
+#include "net/base/net_util.h"
+
+namespace content {
+
+ShellJavaScriptDialogManager::ShellJavaScriptDialogManager() {
+}
+
+ShellJavaScriptDialogManager::~ShellJavaScriptDialogManager() {
+}
+
+void ShellJavaScriptDialogManager::RunJavaScriptDialog(
+ WebContents* web_contents,
+ const GURL& origin_url,
+ const std::string& accept_lang,
+ JavaScriptMessageType javascript_message_type,
+ const string16& message_text,
+ const string16& default_prompt_text,
+ const DialogClosedCallback& callback,
+ bool* did_suppress_message) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+ callback.Run(true, string16());
+ return;
+ }
+
+ if (!dialog_request_callback_.is_null()) {
+ dialog_request_callback_.Run();
+ callback.Run(true, string16());
+ dialog_request_callback_.Reset();
+ return;
+ }
+
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+ *did_suppress_message = false;
+
+ if (dialog_) {
+ // One dialog at a time, please.
+ *did_suppress_message = true;
+ return;
+ }
+
+ string16 new_message_text = net::FormatUrl(origin_url, accept_lang) +
+ ASCIIToUTF16("\n\n") +
+ message_text;
+ gfx::NativeWindow parent_window =
+ web_contents->GetView()->GetTopLevelNativeWindow();
+
+ dialog_.reset(new ShellJavaScriptDialog(this,
+ parent_window,
+ javascript_message_type,
+ new_message_text,
+ default_prompt_text,
+ callback));
+#else
+ // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+ *did_suppress_message = true;
+ return;
+#endif
+}
+
+void ShellJavaScriptDialogManager::RunBeforeUnloadDialog(
+ WebContents* web_contents,
+ const string16& message_text,
+ bool is_reload,
+ const DialogClosedCallback& callback) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+ callback.Run(true, string16());
+ return;
+ }
+
+ if (!dialog_request_callback_.is_null()) {
+ dialog_request_callback_.Run();
+ callback.Run(true, string16());
+ dialog_request_callback_.Reset();
+ return;
+ }
+
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+ if (dialog_) {
+ // Seriously!?
+ callback.Run(true, string16());
+ return;
+ }
+
+ string16 new_message_text =
+ message_text +
+ ASCIIToUTF16("\n\nIs it OK to leave/reload this page?");
+
+ gfx::NativeWindow parent_window =
+ web_contents->GetView()->GetTopLevelNativeWindow();
+
+ dialog_.reset(new ShellJavaScriptDialog(this,
+ parent_window,
+ JAVASCRIPT_MESSAGE_TYPE_CONFIRM,
+ new_message_text,
+ string16(), // default_prompt_text
+ callback));
+#else
+ // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+ callback.Run(true, string16());
+ return;
+#endif
+}
+
+void ShellJavaScriptDialogManager::CancelActiveAndPendingDialogs(
+ WebContents* web_contents) {
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+ if (dialog_) {
+ dialog_->Cancel();
+ dialog_.reset();
+ }
+#else
+ // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+#endif
+}
+
+void ShellJavaScriptDialogManager::WebContentsDestroyed(
+ WebContents* web_contents) {
+}
+
+void ShellJavaScriptDialogManager::DialogClosed(ShellJavaScriptDialog* dialog) {
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+ DCHECK_EQ(dialog, dialog_.get());
+ dialog_.reset();
+#else
+ // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+#endif
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_javascript_dialog_manager.h b/content/shell/browser/shell_javascript_dialog_manager.h
new file mode 100644
index 0000000..763736f
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_manager.h
@@ -0,0 +1,67 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
+#define CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
+
+#include "base/callback_forward.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/javascript_dialog_manager.h"
+
+namespace content {
+
+class ShellJavaScriptDialog;
+
+class ShellJavaScriptDialogManager : public JavaScriptDialogManager {
+ public:
+ ShellJavaScriptDialogManager();
+ virtual ~ShellJavaScriptDialogManager();
+
+ // JavaScriptDialogManager:
+ virtual void RunJavaScriptDialog(
+ WebContents* web_contents,
+ const GURL& origin_url,
+ const std::string& accept_lang,
+ JavaScriptMessageType javascript_message_type,
+ const string16& message_text,
+ const string16& default_prompt_text,
+ const DialogClosedCallback& callback,
+ bool* did_suppress_message) OVERRIDE;
+
+ virtual void RunBeforeUnloadDialog(
+ WebContents* web_contents,
+ const string16& message_text,
+ bool is_reload,
+ const DialogClosedCallback& callback) OVERRIDE;
+
+ virtual void CancelActiveAndPendingDialogs(
+ WebContents* web_contents) OVERRIDE;
+
+ virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
+
+ // Called by the ShellJavaScriptDialog when it closes.
+ void DialogClosed(ShellJavaScriptDialog* dialog);
+
+ // Used for content_browsertests.
+ void set_dialog_request_callback(const base::Closure& callback) {
+ dialog_request_callback_ = callback;
+ }
+
+ private:
+#if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK)
+ // The dialog being shown. No queueing.
+ scoped_ptr<ShellJavaScriptDialog> dialog_;
+#else
+ // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if
+#endif
+
+ base::Closure dialog_request_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellJavaScriptDialogManager);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_JAVASCRIPT_DIALOG_MANAGER_H_
diff --git a/content/shell/browser/shell_javascript_dialog_win.cc b/content/shell/browser/shell_javascript_dialog_win.cc
new file mode 100644
index 0000000..a59639e
--- /dev/null
+++ b/content/shell/browser/shell_javascript_dialog_win.cc
@@ -0,0 +1,113 @@
+// 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_javascript_dialog.h"
+
+#include "base/strings/string_util.h"
+#include "content/shell/app/resource.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_javascript_dialog_manager.h"
+
+namespace content {
+
+class ShellJavaScriptDialog;
+
+INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog,
+ UINT message,
+ WPARAM wparam,
+ LPARAM lparam) {
+ switch (message) {
+ case WM_INITDIALOG: {
+ SetWindowLongPtr(dialog, DWLP_USER, static_cast<LONG_PTR>(lparam));
+ ShellJavaScriptDialog* owner =
+ reinterpret_cast<ShellJavaScriptDialog*>(lparam);
+ owner->dialog_win_ = dialog;
+ SetDlgItemText(dialog, IDC_DIALOGTEXT, owner->message_text_.c_str());
+ if (owner->message_type_ == JAVASCRIPT_MESSAGE_TYPE_PROMPT)
+ SetDlgItemText(dialog, IDC_PROMPTEDIT,
+ owner->default_prompt_text_.c_str());
+ break;
+ }
+ case WM_DESTROY: {
+ ShellJavaScriptDialog* owner = reinterpret_cast<ShellJavaScriptDialog*>(
+ GetWindowLongPtr(dialog, DWLP_USER));
+ if (owner->dialog_win_) {
+ owner->dialog_win_ = 0;
+ owner->callback_.Run(false, string16());
+ owner->manager_->DialogClosed(owner);
+ }
+ break;
+ }
+ case WM_COMMAND: {
+ ShellJavaScriptDialog* owner = reinterpret_cast<ShellJavaScriptDialog*>(
+ GetWindowLongPtr(dialog, DWLP_USER));
+ string16 user_input;
+ bool finish = false;
+ bool result;
+ switch (LOWORD(wparam)) {
+ case IDOK:
+ finish = true;
+ result = true;
+ if (owner->message_type_ == JAVASCRIPT_MESSAGE_TYPE_PROMPT) {
+ int length =
+ GetWindowTextLength(GetDlgItem(dialog, IDC_PROMPTEDIT)) + 1;
+ GetDlgItemText(dialog, IDC_PROMPTEDIT,
+ WriteInto(&user_input, length), length);
+ }
+ break;
+ case IDCANCEL:
+ finish = true;
+ result = false;
+ break;
+ }
+ if (finish) {
+ owner->dialog_win_ = 0;
+ owner->callback_.Run(result, user_input);
+ DestroyWindow(dialog);
+ owner->manager_->DialogClosed(owner);
+ }
+ break;
+ }
+ default:
+ return DefWindowProc(dialog, message, wparam, lparam);
+ }
+ return 0;
+}
+
+ShellJavaScriptDialog::ShellJavaScriptDialog(
+ ShellJavaScriptDialogManager* manager,
+ gfx::NativeWindow parent_window,
+ JavaScriptMessageType message_type,
+ const string16& message_text,
+ const string16& default_prompt_text,
+ const JavaScriptDialogManager::DialogClosedCallback& callback)
+ : manager_(manager),
+ callback_(callback),
+ message_text_(message_text),
+ default_prompt_text_(default_prompt_text),
+ message_type_(message_type) {
+ int dialog_type;
+ if (message_type == JAVASCRIPT_MESSAGE_TYPE_ALERT)
+ dialog_type = IDD_ALERT;
+ else if (message_type == JAVASCRIPT_MESSAGE_TYPE_CONFIRM)
+ dialog_type = IDD_CONFIRM;
+ else // JAVASCRIPT_MESSAGE_TYPE_PROMPT
+ dialog_type = IDD_PROMPT;
+
+ dialog_win_ = CreateDialogParam(GetModuleHandle(0),
+ MAKEINTRESOURCE(dialog_type), 0, DialogProc,
+ reinterpret_cast<LPARAM>(this));
+ ShowWindow(dialog_win_, SW_SHOWNORMAL);
+}
+
+ShellJavaScriptDialog::~ShellJavaScriptDialog() {
+ Cancel();
+}
+
+void ShellJavaScriptDialog::Cancel() {
+ if (dialog_win_)
+ DestroyWindow(dialog_win_);
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_layout_tests_android.cc b/content/shell/browser/shell_layout_tests_android.cc
new file mode 100644
index 0000000..de94b8c
--- /dev/null
+++ b/content/shell/browser/shell_layout_tests_android.cc
@@ -0,0 +1,93 @@
+// 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_layout_tests_android.h"
+
+#include "base/android/fifo_utils.h"
+#include "base/android/jni_android.h"
+#include "base/android/jni_string.h"
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/message_loop/message_loop.h"
+#include "content/public/test/nested_message_pump_android.h"
+#include "content/shell/common/shell_switches.h"
+#include "jni/ShellLayoutTestUtils_jni.h"
+#include "url/gurl.h"
+
+namespace {
+
+// Path to search for when translating a layout test path to an URL.
+const char kAndroidLayoutTestPath[] =
+ "/data/local/tmp/third_party/WebKit/LayoutTests/";
+
+// The base URL from which layout tests are being served on Android.
+const char kAndroidLayoutTestBase[] = "http://127.0.0.1:8000/all-tests/";
+
+base::FilePath GetTestFilesDirectory(JNIEnv* env) {
+ ScopedJavaLocalRef<jstring> directory =
+ content::Java_ShellLayoutTestUtils_getApplicationFilesDirectory(
+ env, base::android::GetApplicationContext());
+ return base::FilePath(ConvertJavaStringToUTF8(directory));
+}
+
+void EnsureCreateFIFO(const base::FilePath& path) {
+ unlink(path.value().c_str());
+ CHECK(base::android::CreateFIFO(path, 0666))
+ << "Unable to create the Android's FIFO: " << path.value().c_str();
+}
+
+base::MessagePump* CreateMessagePumpForUI() {
+ return new content::NestedMessagePumpAndroid();
+}
+
+} // namespace
+
+namespace content {
+
+bool GetTestUrlForAndroid(std::string& path_or_url, GURL* url) {
+ if (path_or_url.find(kAndroidLayoutTestPath) == std::string::npos)
+ return false;
+
+ std::string test_location(kAndroidLayoutTestBase);
+ test_location.append(path_or_url.substr(strlen(kAndroidLayoutTestPath)));
+
+ *url = GURL(test_location);
+ return true;
+}
+
+void EnsureInitializeForAndroidLayoutTests() {
+ CHECK(CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree));
+
+ JNIEnv* env = base::android::AttachCurrentThread();
+ content::NestedMessagePumpAndroid::RegisterJni(env);
+ content::RegisterNativesImpl(env);
+
+ bool success = base::MessageLoop::InitMessagePumpForUIFactory(
+ &CreateMessagePumpForUI);
+ CHECK(success) << "Unable to initialize the message pump for Android.";
+
+ // Android will need three FIFOs to communicate with the Blink test runner,
+ // one for each of [stdout, stderr, stdin].
+ base::FilePath files_dir(GetTestFilesDirectory(env));
+
+ base::FilePath stdout_fifo(files_dir.Append(FILE_PATH_LITERAL("test.fifo")));
+ EnsureCreateFIFO(stdout_fifo);
+
+ base::FilePath stderr_fifo(
+ files_dir.Append(FILE_PATH_LITERAL("stderr.fifo")));
+ EnsureCreateFIFO(stderr_fifo);
+
+ base::FilePath stdin_fifo(files_dir.Append(FILE_PATH_LITERAL("stdin.fifo")));
+ EnsureCreateFIFO(stdin_fifo);
+
+ // Redirecting stdout needs to happen before redirecting stdin, which needs
+ // to happen before redirecting stderr.
+ success = base::android::RedirectStream(stdout, stdout_fifo, "w") &&
+ base::android::RedirectStream(stdin, stdin_fifo, "r") &&
+ base::android::RedirectStream(stderr, stderr_fifo, "w");
+
+ CHECK(success) << "Unable to initialize the Android FIFOs.";
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_layout_tests_android.h b/content/shell/browser/shell_layout_tests_android.h
new file mode 100644
index 0000000..7410954
--- /dev/null
+++ b/content/shell/browser/shell_layout_tests_android.h
@@ -0,0 +1,25 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_LAYOUT_TESTS_ANDROID_H_
+#define CONTENT_SHELL_BROWSER_SHELL_LAYOUT_TESTS_ANDROID_H_
+
+#include <string>
+
+class GURL;
+
+namespace content {
+
+// On Android, all passed tests will be paths to a local temporary directory.
+// However, because we can't transfer all test files to the device, translate
+// those paths to a local, forwarded URL so the host can serve them.
+bool GetTestUrlForAndroid(std::string& path_or_url, GURL* url);
+
+// Initialize the nested message loop and FIFOs for Android, and verify that
+// all has been set up using a few appropriate CHECK()s.
+void EnsureInitializeForAndroidLayoutTests();
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_LAYOUT_TESTS_ANDROID_H_
diff --git a/content/shell/browser/shell_login_dialog.cc b/content/shell/browser/shell_login_dialog.cc
new file mode 100644
index 0000000..f1639e9
--- /dev/null
+++ b/content/shell/browser/shell_login_dialog.cc
@@ -0,0 +1,107 @@
+// 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_login_dialog.h"
+
+#include "base/bind.h"
+#include "base/logging.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/resource_dispatcher_host.h"
+#include "net/base/auth.h"
+#include "net/url_request/url_request.h"
+#include "ui/base/text/text_elider.h"
+
+namespace content {
+
+ShellLoginDialog::ShellLoginDialog(
+ net::AuthChallengeInfo* auth_info,
+ net::URLRequest* request) : auth_info_(auth_info),
+ request_(request) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&ShellLoginDialog::PrepDialog, this,
+ ASCIIToUTF16(auth_info->challenger.ToString()),
+ UTF8ToUTF16(auth_info->realm)));
+}
+
+void ShellLoginDialog::OnRequestCancelled() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&ShellLoginDialog::PlatformRequestCancelled, this));
+}
+
+void ShellLoginDialog::UserAcceptedAuth(const string16& username,
+ const string16& password) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ShellLoginDialog::SendAuthToRequester, this,
+ true, username, password));
+}
+
+void ShellLoginDialog::UserCancelledAuth() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ BrowserThread::PostTask(
+ BrowserThread::IO, FROM_HERE,
+ base::Bind(&ShellLoginDialog::SendAuthToRequester, this,
+ false, string16(), string16()));
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&ShellLoginDialog::PlatformCleanUp, this));
+}
+
+ShellLoginDialog::~ShellLoginDialog() {
+ // Cannot post any tasks here; this object is going away and cannot be
+ // referenced/dereferenced.
+}
+
+#if !defined(OS_MACOSX) && !defined(TOOLKIT_GTK)
+// Bogus implementations for linking. They are never called because
+// ResourceDispatcherHostDelegate::CreateLoginDelegate returns NULL.
+// TODO: implement ShellLoginDialog for other platforms, drop this #if
+void ShellLoginDialog::PlatformCreateDialog(const string16& message) {}
+void ShellLoginDialog::PlatformCleanUp() {}
+void ShellLoginDialog::PlatformRequestCancelled() {}
+#endif
+
+void ShellLoginDialog::PrepDialog(const string16& host,
+ const string16& realm) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ // The realm is controlled by the remote server, so there is no reason to
+ // believe it is of a reasonable length.
+ string16 elided_realm;
+ ui::ElideString(realm, 120, &elided_realm);
+
+ string16 explanation =
+ ASCIIToUTF16("The server ") + host +
+ ASCIIToUTF16(" requires a username and password.");
+
+ if (!elided_realm.empty()) {
+ explanation += ASCIIToUTF16(" The server says: ");
+ explanation += elided_realm;
+ explanation += ASCIIToUTF16(".");
+ }
+
+ PlatformCreateDialog(explanation);
+}
+
+void ShellLoginDialog::SendAuthToRequester(bool success,
+ const string16& username,
+ const string16& password) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+ if (success)
+ request_->SetAuth(net::AuthCredentials(username, password));
+ else
+ request_->CancelAuth();
+ ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request_);
+
+ BrowserThread::PostTask(
+ BrowserThread::UI, FROM_HERE,
+ base::Bind(&ShellLoginDialog::PlatformCleanUp, this));
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_login_dialog.h b/content/shell/browser/shell_login_dialog.h
new file mode 100644
index 0000000..d9b0504
--- /dev/null
+++ b/content/shell/browser/shell_login_dialog.h
@@ -0,0 +1,97 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_
+#define CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_
+
+#include "base/compiler_specific.h"
+#include "base/strings/string16.h"
+#include "content/public/browser/resource_dispatcher_host_login_delegate.h"
+
+#if defined(TOOLKIT_GTK)
+#include "ui/base/gtk/gtk_signal.h"
+#endif
+
+#if defined(OS_MACOSX)
+#if __OBJC__
+@class ShellLoginDialogHelper;
+#else
+class ShellLoginDialogHelper;
+#endif // __OBJC__
+#endif // defined(OS_MACOSX)
+
+namespace net {
+class AuthChallengeInfo;
+class URLRequest;
+}
+
+namespace content {
+
+// This class provides a dialog box to ask the user for credentials. Useful in
+// ResourceDispatcherHostDelegate::CreateLoginDelegate.
+class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate {
+ public:
+ // Threading: IO thread.
+ ShellLoginDialog(net::AuthChallengeInfo* auth_info, net::URLRequest* request);
+
+ // ResourceDispatcherHostLoginDelegate implementation:
+ // Threading: IO thread.
+ virtual void OnRequestCancelled() OVERRIDE;
+
+ // Called by the platform specific code when the user responds. Public because
+ // the aforementioned platform specific code may not have access to private
+ // members. Not to be called from client code.
+ // Threading: UI thread.
+ void UserAcceptedAuth(const string16& username, const string16& password);
+ void UserCancelledAuth();
+
+ protected:
+ // Threading: any
+ virtual ~ShellLoginDialog();
+
+ private:
+ // All the methods that begin with Platform need to be implemented by the
+ // platform specific LoginDialog implementation.
+ // Creates the dialog.
+ // Threading: UI thread.
+ void PlatformCreateDialog(const string16& message);
+ // Called from the destructor to let each platform do any necessary cleanup.
+ // Threading: UI thread.
+ void PlatformCleanUp();
+ // Called from OnRequestCancelled if the request was cancelled.
+ // Threading: UI thread.
+ void PlatformRequestCancelled();
+
+ // Sets up dialog creation.
+ // Threading: UI thread.
+ void PrepDialog(const string16& host, const string16& realm);
+
+ // Sends the authentication to the requester.
+ // Threading: IO thread.
+ void SendAuthToRequester(bool success,
+ const string16& username,
+ const string16& password);
+
+ // Who/where/what asked for the authentication.
+ // Threading: IO thread.
+ scoped_refptr<net::AuthChallengeInfo> auth_info_;
+
+ // The request that wants login data.
+ // Threading: IO thread.
+ net::URLRequest* request_;
+
+#if defined(OS_MACOSX)
+ // Threading: UI thread.
+ ShellLoginDialogHelper* helper_; // owned
+#elif defined(TOOLKIT_GTK)
+ GtkWidget* username_entry_;
+ GtkWidget* password_entry_;
+ GtkWidget* root_;
+ CHROMEGTK_CALLBACK_1(ShellLoginDialog, void, OnResponse, int);
+#endif
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_
diff --git a/content/shell/browser/shell_login_dialog_gtk.cc b/content/shell/browser/shell_login_dialog_gtk.cc
new file mode 100644
index 0000000..b08b449
--- /dev/null
+++ b/content/shell/browser/shell_login_dialog_gtk.cc
@@ -0,0 +1,111 @@
+// 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_login_dialog.h"
+
+#include <gtk/gtk.h>
+
+#include "base/logging.h"
+#include "base/strings/string16.h"
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/resource_dispatcher_host.h"
+#include "content/public/browser/resource_request_info.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "ui/base/gtk/gtk_hig_constants.h"
+
+namespace content {
+
+void ShellLoginDialog::PlatformCreateDialog(const string16& message) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ int render_process_id;
+ int render_view_id;
+ if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderView(
+ &render_process_id, &render_view_id)) {
+ NOTREACHED();
+ }
+
+ WebContents* web_contents = NULL;
+ RenderViewHost* render_view_host =
+ RenderViewHost::FromID(render_process_id, render_view_id);
+ if (render_view_host)
+ web_contents = WebContents::FromRenderViewHost(render_view_host);
+ DCHECK(web_contents);
+
+ gfx::NativeWindow parent_window =
+ web_contents->GetView()->GetTopLevelNativeWindow();
+
+ root_ = gtk_message_dialog_new(parent_window,
+ GTK_DIALOG_MODAL,
+ GTK_MESSAGE_INFO,
+ GTK_BUTTONS_OK_CANCEL,
+ "Please log in.");
+
+ GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(root_));
+ GtkWidget* label = gtk_label_new(UTF16ToUTF8(message).c_str());
+ gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+ gtk_box_pack_start(GTK_BOX(content_area), label, FALSE, FALSE, 0);
+
+ username_entry_ = gtk_entry_new();
+ gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE);
+
+ password_entry_ = gtk_entry_new();
+ gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
+ gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);
+
+ GtkWidget* table = gtk_table_new(2, 2, FALSE);
+ gtk_table_set_col_spacing(GTK_TABLE(table), 0, ui::kLabelSpacing);
+ gtk_table_set_row_spacings(GTK_TABLE(table), ui::kControlSpacing);
+
+ GtkWidget* username_label = gtk_label_new("Username:");
+ gtk_misc_set_alignment(GTK_MISC(username_label), 0, 0.5);
+
+ gtk_table_attach(GTK_TABLE(table), username_label, 0, 1, 0, 1, GTK_FILL,
+ GTK_FILL, 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), username_entry_, 1, 2, 0, 1);
+
+ GtkWidget* password_label = gtk_label_new("Password:");
+ gtk_misc_set_alignment(GTK_MISC(password_label), 0, 0.5);
+
+ gtk_table_attach(GTK_TABLE(table), password_label, 0, 1, 1, 2, GTK_FILL,
+ GTK_FILL, 0, 0);
+ gtk_table_attach_defaults(GTK_TABLE(table), password_entry_, 1, 2, 1, 2);
+
+ gtk_box_pack_start(GTK_BOX(content_area), table, FALSE, FALSE, 0);
+
+ g_signal_connect(root_, "response", G_CALLBACK(OnResponseThunk), this);
+ gtk_widget_grab_focus(username_entry_);
+ gtk_widget_show_all(GTK_WIDGET(root_));
+}
+
+void ShellLoginDialog::PlatformCleanUp() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void ShellLoginDialog::PlatformRequestCancelled() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+}
+
+void ShellLoginDialog::OnResponse(GtkWidget* sender, int response_id) {
+ switch (response_id) {
+ case GTK_RESPONSE_OK:
+ UserAcceptedAuth(
+ UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))),
+ UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_))));
+ break;
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
+ UserCancelledAuth();
+ break;
+ default:
+ NOTREACHED();
+ }
+
+ gtk_widget_destroy(root_);
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_login_dialog_mac.mm b/content/shell/browser/shell_login_dialog_mac.mm
new file mode 100644
index 0000000..447aa58
--- /dev/null
+++ b/content/shell/browser/shell_login_dialog_mac.mm
@@ -0,0 +1,122 @@
+// 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_login_dialog.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/logging.h"
+#include "base/mac/bundle_locations.h"
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/sys_string_conversions.h"
+#include "content/public/browser/browser_thread.h"
+#import "ui/base/cocoa/nib_loading.h"
+
+namespace {
+
+const int kUsernameFieldTag = 1;
+const int kPasswordFieldTag = 2;
+
+} // namespace
+
+// Helper object that receives the notification that the dialog/sheet is
+// going away.
+@interface ShellLoginDialogHelper : NSObject<NSAlertDelegate> {
+ @private
+ base::scoped_nsobject<NSAlert> alert_;
+ NSTextField* usernameField_; // WEAK; owned by alert_
+ NSSecureTextField* passwordField_; // WEAK; owned by alert_
+}
+
+- (NSAlert*)alert;
+- (NSView*)accessoryView;
+- (void)focus;
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo;
+- (void)cancel;
+
+@end
+
+@implementation ShellLoginDialogHelper
+
+- (NSAlert*)alert {
+ alert_.reset([[NSAlert alloc] init]);
+ [alert_ setAccessoryView:[self accessoryView]];
+ return alert_;
+}
+
+- (NSView*)accessoryView {
+ NSView* accessory_view = ui::GetViewFromNib(@"HttpAuth");
+ if (!accessory_view)
+ return nil;
+
+ usernameField_ = [accessory_view viewWithTag:kUsernameFieldTag];
+ passwordField_ = [accessory_view viewWithTag:kPasswordFieldTag];
+ return accessory_view;
+}
+
+- (void)focus {
+ [[alert_ window] makeFirstResponder:usernameField_];
+}
+
+- (void)alertDidEnd:(NSAlert*)alert
+ returnCode:(int)returnCode
+ contextInfo:(void*)contextInfo {
+ if (returnCode == NSRunStoppedResponse)
+ return;
+
+ content::ShellLoginDialog* this_dialog =
+ reinterpret_cast<content::ShellLoginDialog*>(contextInfo);
+ if (returnCode == NSAlertFirstButtonReturn) {
+ this_dialog->UserAcceptedAuth(
+ base::SysNSStringToUTF16([usernameField_ stringValue]),
+ base::SysNSStringToUTF16([passwordField_ stringValue]));
+ } else {
+ this_dialog->UserCancelledAuth();
+ }
+}
+
+- (void)cancel {
+ [NSApp endSheet:[alert_ window]];
+ alert_.reset();
+}
+
+@end
+
+namespace content {
+
+void ShellLoginDialog::PlatformCreateDialog(const string16& message) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ helper_ = [[ShellLoginDialogHelper alloc] init];
+
+ // Show the modal dialog.
+ NSAlert* alert = [helper_ alert];
+ [alert setDelegate:helper_];
+ [alert setInformativeText:base::SysUTF16ToNSString(message)];
+ [alert setMessageText:@"Please log in."];
+ [alert addButtonWithTitle:@"OK"];
+ NSButton* other = [alert addButtonWithTitle:@"Cancel"];
+ [other setKeyEquivalent:@"\e"];
+ [alert
+ beginSheetModalForWindow:nil // nil here makes it app-modal
+ modalDelegate:helper_
+ didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
+ contextInfo:this];
+
+ [helper_ focus];
+}
+
+void ShellLoginDialog::PlatformCleanUp() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ [helper_ release];
+ helper_ = nil;
+}
+
+void ShellLoginDialog::PlatformRequestCancelled() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ [helper_ cancel];
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_mac.mm b/content/shell/browser/shell_mac.mm
new file mode 100644
index 0000000..ca6a0ff
--- /dev/null
+++ b/content/shell/browser/shell_mac.mm
@@ -0,0 +1,334 @@
+// 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 <algorithm>
+
+#include "base/logging.h"
+#import "base/mac/scoped_nsobject.h"
+#include "base/strings/string_piece.h"
+#include "base/strings/sys_string_conversions.h"
+#include "content/public/browser/native_web_keyboard_event.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/shell/app/resource.h"
+#import "ui/base/cocoa/underlay_opengl_hosting_window.h"
+#include "url/gurl.h"
+
+#if !defined(MAC_OS_X_VERSION_10_7) || \
+ MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7
+
+enum {
+ NSWindowCollectionBehaviorFullScreenPrimary = 1 << 7,
+ NSWindowCollectionBehaviorFullScreenAuxiliary = 1 << 8
+};
+
+#endif // MAC_OS_X_VERSION_10_7
+
+// Receives notification that the window is closing so that it can start the
+// tear-down process. Is responsible for deleting itself when done.
+@interface ContentShellWindowDelegate : NSObject<NSWindowDelegate> {
+ @private
+ content::Shell* shell_;
+}
+- (id)initWithShell:(content::Shell*)shell;
+@end
+
+@implementation ContentShellWindowDelegate
+
+- (id)initWithShell:(content::Shell*)shell {
+ if ((self = [super init])) {
+ shell_ = shell;
+ }
+ return self;
+}
+
+// Called when the window is about to close. Perform the self-destruction
+// sequence by getting rid of the shell and removing it and the window from
+// the various global lists. By returning YES, we allow the window to be
+// removed from the screen.
+- (BOOL)windowShouldClose:(id)window {
+ [window autorelease];
+ delete shell_;
+ [self release];
+
+ return YES;
+}
+
+- (void)performAction:(id)sender {
+ shell_->ActionPerformed([sender tag]);
+}
+
+- (void)takeURLStringValueFrom:(id)sender {
+ shell_->URLEntered(base::SysNSStringToUTF8([sender stringValue]));
+}
+
+@end
+
+@interface CrShellWindow : UnderlayOpenGLHostingWindow {
+ @private
+ content::Shell* shell_;
+}
+- (void)setShell:(content::Shell*)shell;
+- (void)showDevTools:(id)sender;
+@end
+
+@implementation CrShellWindow
+
+- (void)setShell:(content::Shell*)shell {
+ shell_ = shell;
+}
+
+- (void)showDevTools:(id)sender {
+ shell_->ShowDevTools();
+}
+
+@end
+
+namespace {
+
+NSString* kWindowTitle = @"Content Shell";
+
+// Layout constants (in view coordinates)
+const CGFloat kButtonWidth = 72;
+const CGFloat kURLBarHeight = 24;
+
+// The minimum size of the window's content (in view coordinates)
+const CGFloat kMinimumWindowWidth = 400;
+const CGFloat kMinimumWindowHeight = 300;
+
+void MakeShellButton(NSRect* rect,
+ NSString* title,
+ NSView* parent,
+ int control,
+ NSView* target,
+ NSString* key,
+ NSUInteger modifier) {
+ base::scoped_nsobject<NSButton> button(
+ [[NSButton alloc] initWithFrame:*rect]);
+ [button setTitle:title];
+ [button setBezelStyle:NSSmallSquareBezelStyle];
+ [button setAutoresizingMask:(NSViewMaxXMargin | NSViewMinYMargin)];
+ [button setTarget:target];
+ [button setAction:@selector(performAction:)];
+ [button setTag:control];
+ [button setKeyEquivalent:key];
+ [button setKeyEquivalentModifierMask:modifier];
+ [parent addSubview:button];
+ rect->origin.x += kButtonWidth;
+}
+
+} // namespace
+
+namespace content {
+
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+}
+
+void Shell::PlatformCleanUp() {
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+ if (headless_)
+ return;
+
+ int id;
+ switch (control) {
+ case BACK_BUTTON:
+ id = IDC_NAV_BACK;
+ break;
+ case FORWARD_BUTTON:
+ id = IDC_NAV_FORWARD;
+ break;
+ case STOP_BUTTON:
+ id = IDC_NAV_STOP;
+ break;
+ default:
+ NOTREACHED() << "Unknown UI control";
+ return;
+ }
+ [[[window_ contentView] viewWithTag:id] setEnabled:is_enabled];
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+ if (headless_)
+ return;
+
+ NSString* url_string = base::SysUTF8ToNSString(url.spec());
+ [url_edit_view_ setStringValue:url_string];
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+ if (headless_) {
+ content_width_ = width;
+ content_height_ = height;
+ return;
+ }
+
+ NSRect initial_window_bounds =
+ NSMakeRect(0, 0, width, height + kURLBarHeight);
+ NSRect content_rect = initial_window_bounds;
+ NSUInteger style_mask = NSTitledWindowMask |
+ NSClosableWindowMask |
+ NSMiniaturizableWindowMask |
+ NSResizableWindowMask;
+ CrShellWindow* window =
+ [[CrShellWindow alloc] initWithContentRect:content_rect
+ styleMask:style_mask
+ backing:NSBackingStoreBuffered
+ defer:NO];
+ window_ = window;
+ [window setShell:this];
+ [window_ setTitle:kWindowTitle];
+ NSView* content = [window_ contentView];
+
+ // If the window is allowed to get too small, it will wreck the view bindings.
+ NSSize min_size = NSMakeSize(kMinimumWindowWidth, kMinimumWindowHeight);
+ min_size = [content convertSize:min_size toView:nil];
+ // Note that this takes window coordinates.
+ [window_ setContentMinSize:min_size];
+
+ // Set the shell window to participate in Lion Fullscreen mode. Set
+ // Setting this flag has no effect on Snow Leopard or earlier.
+ NSUInteger collectionBehavior = [window_ collectionBehavior];
+ collectionBehavior |= NSWindowCollectionBehaviorFullScreenPrimary;
+ [window_ setCollectionBehavior:collectionBehavior];
+
+ // Rely on the window delegate to clean us up rather than immediately
+ // releasing when the window gets closed. We use the delegate to do
+ // everything from the autorelease pool so the shell isn't on the stack
+ // during cleanup (ie, a window close from javascript).
+ [window_ setReleasedWhenClosed:NO];
+
+ // Create a window delegate to watch for when it's asked to go away. It will
+ // clean itself up so we don't need to hold a reference.
+ ContentShellWindowDelegate* delegate =
+ [[ContentShellWindowDelegate alloc] initWithShell:this];
+ [window_ setDelegate:delegate];
+
+ NSRect button_frame =
+ NSMakeRect(0, NSMaxY(initial_window_bounds) - kURLBarHeight,
+ kButtonWidth, kURLBarHeight);
+
+ MakeShellButton(&button_frame, @"Back", content, IDC_NAV_BACK,
+ (NSView*)delegate, @"[", NSCommandKeyMask);
+ MakeShellButton(&button_frame, @"Forward", content, IDC_NAV_FORWARD,
+ (NSView*)delegate, @"]", NSCommandKeyMask);
+ MakeShellButton(&button_frame, @"Reload", content, IDC_NAV_RELOAD,
+ (NSView*)delegate, @"r", NSCommandKeyMask);
+ MakeShellButton(&button_frame, @"Stop", content, IDC_NAV_STOP,
+ (NSView*)delegate, @".", NSCommandKeyMask);
+
+ button_frame.size.width =
+ NSWidth(initial_window_bounds) - NSMinX(button_frame);
+ base::scoped_nsobject<NSTextField> url_edit_view(
+ [[NSTextField alloc] initWithFrame:button_frame]);
+ [content addSubview:url_edit_view];
+ [url_edit_view setAutoresizingMask:(NSViewWidthSizable | NSViewMinYMargin)];
+ [url_edit_view setTarget:delegate];
+ [url_edit_view setAction:@selector(takeURLStringValueFrom:)];
+ [[url_edit_view cell] setWraps:NO];
+ [[url_edit_view cell] setScrollable:YES];
+ url_edit_view_ = url_edit_view.get();
+
+ // show the window
+ [window_ makeKeyAndOrderFront:nil];
+}
+
+void Shell::PlatformSetContents() {
+ NSView* web_view = web_contents_->GetView()->GetNativeView();
+ [web_view setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+
+ if (headless_) {
+ SizeTo(content_width_, content_height_);
+ return;
+ }
+
+ NSView* content = [window_ contentView];
+ [content addSubview:web_view];
+
+ NSRect frame = [content bounds];
+ frame.size.height -= kURLBarHeight;
+ [web_view setFrame:frame];
+ [web_view setNeedsDisplay:YES];
+}
+
+void Shell::SizeTo(int width, int height) {
+ if (!headless_) {
+ NOTREACHED();
+ return;
+ }
+ NSView* web_view = web_contents_->GetView()->GetNativeView();
+ NSRect frame = NSMakeRect(0, 0, width, height);
+ [web_view setFrame:frame];
+}
+
+void Shell::PlatformResizeSubViews() {
+ // Not needed; subviews are bound.
+}
+
+void Shell::PlatformSetTitle(const string16& title) {
+ if (headless_)
+ return;
+
+ NSString* title_string = base::SysUTF16ToNSString(title);
+ [window_ setTitle:title_string];
+}
+
+void Shell::Close() {
+ if (headless_)
+ delete this;
+ else
+ [window_ performClose:nil];
+}
+
+void Shell::ActionPerformed(int control) {
+ switch (control) {
+ case IDC_NAV_BACK:
+ GoBackOrForward(-1);
+ break;
+ case IDC_NAV_FORWARD:
+ GoBackOrForward(1);
+ break;
+ case IDC_NAV_RELOAD:
+ Reload();
+ break;
+ case IDC_NAV_STOP:
+ Stop();
+ break;
+ }
+}
+
+void Shell::URLEntered(std::string url_string) {
+ if (!url_string.empty()) {
+ GURL url(url_string);
+ if (!url.has_scheme())
+ url = GURL("http://" + url_string);
+ LoadURL(url);
+ }
+}
+
+void Shell::HandleKeyboardEvent(WebContents* source,
+ const NativeWebKeyboardEvent& event) {
+ if (event.skip_in_browser)
+ return;
+
+ // The event handling to get this strictly right is a tangle; cheat here a bit
+ // by just letting the menus have a chance at it.
+ if ([event.os_event type] == NSKeyDown) {
+ if (([event.os_event modifierFlags] & NSCommandKeyMask) &&
+ [[event.os_event characters] isEqual:@"l"]) {
+ [window_ makeFirstResponder:url_edit_view_];
+ return;
+ }
+
+ [[NSApp mainMenu] performKeyEquivalent:event.os_event];
+ }
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_message_filter.cc b/content/shell/browser/shell_message_filter.cc
new file mode 100644
index 0000000..c7c4cca
--- /dev/null
+++ b/content/shell/browser/shell_message_filter.cc
@@ -0,0 +1,105 @@
+// 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_message_filter.h"
+
+#include "base/file_util.h"
+#include "base/threading/thread_restrictions.h"
+#include "content/public/browser/child_process_security_policy.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/browser/shell_network_delegate.h"
+#include "content/shell/common/shell_messages.h"
+#include "net/base/net_errors.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "webkit/browser/database/database_tracker.h"
+#include "webkit/browser/fileapi/isolated_context.h"
+#include "webkit/browser/quota/quota_manager.h"
+
+namespace content {
+
+ShellMessageFilter::ShellMessageFilter(
+ int render_process_id,
+ webkit_database::DatabaseTracker* database_tracker,
+ quota::QuotaManager* quota_manager,
+ net::URLRequestContextGetter* request_context_getter)
+ : render_process_id_(render_process_id),
+ database_tracker_(database_tracker),
+ quota_manager_(quota_manager),
+ request_context_getter_(request_context_getter) {
+}
+
+ShellMessageFilter::~ShellMessageFilter() {
+}
+
+void ShellMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) {
+ if (message.type() == ShellViewHostMsg_ClearAllDatabases::ID)
+ *thread = BrowserThread::FILE;
+}
+
+bool ShellMessageFilter::OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) {
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP_EX(ShellMessageFilter, message, *message_was_ok)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_ReadFileToString, OnReadFileToString)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_RegisterIsolatedFileSystem,
+ OnRegisterIsolatedFileSystem)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_ClearAllDatabases, OnClearAllDatabases)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_SetDatabaseQuota, OnSetDatabaseQuota)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_AcceptAllCookies, OnAcceptAllCookies)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_DeleteAllCookies, OnDeleteAllCookies)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void ShellMessageFilter::OnReadFileToString(const base::FilePath& local_file,
+ std::string* contents) {
+ base::ThreadRestrictions::ScopedAllowIO allow_io;
+ file_util::ReadFileToString(local_file, contents);
+}
+
+void ShellMessageFilter::OnRegisterIsolatedFileSystem(
+ const std::vector<base::FilePath>& absolute_filenames,
+ std::string* filesystem_id) {
+ fileapi::IsolatedContext::FileInfoSet files;
+ ChildProcessSecurityPolicy* policy =
+ ChildProcessSecurityPolicy::GetInstance();
+ for (size_t i = 0; i < absolute_filenames.size(); ++i) {
+ files.AddPath(absolute_filenames[i], NULL);
+ if (!policy->CanReadFile(render_process_id_, absolute_filenames[i]))
+ policy->GrantReadFile(render_process_id_, absolute_filenames[i]);
+ }
+ *filesystem_id =
+ fileapi::IsolatedContext::GetInstance()->RegisterDraggedFileSystem(files);
+ policy->GrantReadFileSystem(render_process_id_, *filesystem_id);
+}
+
+void ShellMessageFilter::OnClearAllDatabases() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
+ database_tracker_->DeleteDataModifiedSince(
+ base::Time(), net::CompletionCallback());
+}
+
+void ShellMessageFilter::OnSetDatabaseQuota(int quota) {
+ quota_manager_->SetTemporaryGlobalOverrideQuota(
+ quota * quota::QuotaManager::kPerHostTemporaryPortion,
+ quota::QuotaCallback());
+}
+
+void ShellMessageFilter::OnAcceptAllCookies(bool accept) {
+ ShellNetworkDelegate::SetAcceptAllCookies(accept);
+}
+
+void ShellMessageFilter::OnDeleteAllCookies() {
+ request_context_getter_->GetURLRequestContext()->cookie_store()
+ ->GetCookieMonster()
+ ->DeleteAllAsync(net::CookieMonster::DeleteCallback());
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_message_filter.h b/content/shell/browser/shell_message_filter.h
new file mode 100644
index 0000000..135a915
--- /dev/null
+++ b/content/shell/browser/shell_message_filter.h
@@ -0,0 +1,66 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_MESSAGE_FILTER_H_
+#define CONTENT_SHELL_BROWSER_SHELL_MESSAGE_FILTER_H_
+
+#include <string>
+#include <vector>
+
+#include "base/basictypes.h"
+#include "base/files/file_path.h"
+#include "content/public/browser/browser_message_filter.h"
+
+namespace net {
+class URLRequestContextGetter;
+}
+
+namespace quota {
+class QuotaManager;
+}
+
+namespace webkit_database {
+class DatabaseTracker;
+}
+
+namespace content {
+
+class ShellMessageFilter : public BrowserMessageFilter {
+ public:
+ ShellMessageFilter(int render_process_id,
+ webkit_database::DatabaseTracker* database_tracker,
+ quota::QuotaManager* quota_manager,
+ net::URLRequestContextGetter* request_context_getter);
+
+ private:
+ virtual ~ShellMessageFilter();
+
+ // BrowserMessageFilter implementation.
+ virtual void OverrideThreadForMessage(const IPC::Message& message,
+ BrowserThread::ID* thread) OVERRIDE;
+ virtual bool OnMessageReceived(const IPC::Message& message,
+ bool* message_was_ok) OVERRIDE;
+
+ void OnReadFileToString(const base::FilePath& local_file,
+ std::string* contents);
+ void OnRegisterIsolatedFileSystem(
+ const std::vector<base::FilePath>& absolute_filenames,
+ std::string* filesystem_id);
+ void OnClearAllDatabases();
+ void OnSetDatabaseQuota(int quota);
+ void OnAcceptAllCookies(bool accept);
+ void OnDeleteAllCookies();
+
+ int render_process_id_;
+
+ webkit_database::DatabaseTracker* database_tracker_;
+ quota::QuotaManager* quota_manager_;
+ net::URLRequestContextGetter* request_context_getter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellMessageFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_MESSAGE_FILTER_H_
diff --git a/content/shell/browser/shell_net_log.cc b/content/shell/browser/shell_net_log.cc
new file mode 100644
index 0000000..97276d6
--- /dev/null
+++ b/content/shell/browser/shell_net_log.cc
@@ -0,0 +1,72 @@
+// 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_net_log.h"
+
+#include <stdio.h>
+
+#include "base/command_line.h"
+#include "base/files/file_path.h"
+#include "base/values.h"
+#include "content/public/common/content_switches.h"
+#include "net/base/net_log_logger.h"
+
+namespace content {
+
+namespace {
+
+base::DictionaryValue* GetShellConstants() {
+ base::DictionaryValue* constants_dict = net::NetLogLogger::GetConstants();
+
+ // Add a dictionary with client information
+ base::DictionaryValue* dict = new DictionaryValue();
+
+ dict->SetString("name", "content_shell");
+ dict->SetString("command_line",
+ CommandLine::ForCurrentProcess()->GetCommandLineString());
+
+ constants_dict->Set("clientInfo", dict);
+
+ return constants_dict;
+}
+
+} // namespace
+
+ShellNetLog::ShellNetLog() {
+ const CommandLine* command_line = CommandLine::ForCurrentProcess();
+
+ if (command_line->HasSwitch(switches::kLogNetLog)) {
+ base::FilePath log_path =
+ command_line->GetSwitchValuePath(switches::kLogNetLog);
+ // Much like logging.h, bypass threading restrictions by using fopen
+ // directly. Have to write on a thread that's shutdown to handle events on
+ // shutdown properly, and posting events to another thread as they occur
+ // would result in an unbounded buffer size, so not much can be gained by
+ // doing this on another thread. It's only used when debugging, so
+ // performance is not a big concern.
+ FILE* file = NULL;
+#if defined(OS_WIN)
+ file = _wfopen(log_path.value().c_str(), L"w");
+#elif defined(OS_POSIX)
+ file = fopen(log_path.value().c_str(), "w");
+#endif
+
+ if (file == NULL) {
+ LOG(ERROR) << "Could not open file " << log_path.value()
+ << " for net logging";
+ } else {
+ scoped_ptr<base::Value> constants(GetShellConstants());
+ net_log_logger_.reset(new net::NetLogLogger(file, *constants));
+ net_log_logger_->StartObserving(this);
+ }
+ }
+}
+
+ShellNetLog::~ShellNetLog() {
+ // Remove the observer we own before we're destroyed.
+ if (net_log_logger_)
+ RemoveThreadSafeObserver(net_log_logger_.get());
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_net_log.h b/content/shell/browser/shell_net_log.h
new file mode 100644
index 0000000..9846917
--- /dev/null
+++ b/content/shell/browser/shell_net_log.h
@@ -0,0 +1,28 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_NET_LOG_H_
+#define CONTENT_SHELL_BROWSER_SHELL_NET_LOG_H_
+
+#include <string>
+
+#include "base/memory/scoped_ptr.h"
+#include "net/base/net_log_logger.h"
+
+namespace content {
+
+class ShellNetLog : public net::NetLog {
+ public:
+ ShellNetLog();
+ virtual ~ShellNetLog();
+
+ private:
+ scoped_ptr<net::NetLogLogger> net_log_logger_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellNetLog);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_NET_LOG_H_
diff --git a/content/shell/browser/shell_network_delegate.cc b/content/shell/browser/shell_network_delegate.cc
new file mode 100644
index 0000000..560426f
--- /dev/null
+++ b/content/shell/browser/shell_network_delegate.cc
@@ -0,0 +1,127 @@
+// 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_network_delegate.h"
+
+#include "net/base/net_errors.h"
+#include "net/base/static_cookie_policy.h"
+#include "net/url_request/url_request.h"
+
+namespace content {
+
+namespace {
+bool g_accept_all_cookies = true;
+}
+
+ShellNetworkDelegate::ShellNetworkDelegate() {
+}
+
+ShellNetworkDelegate::~ShellNetworkDelegate() {
+}
+
+void ShellNetworkDelegate::SetAcceptAllCookies(bool accept) {
+ g_accept_all_cookies = accept;
+}
+
+int ShellNetworkDelegate::OnBeforeURLRequest(
+ net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ GURL* new_url) {
+ return net::OK;
+}
+
+int ShellNetworkDelegate::OnBeforeSendHeaders(
+ net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ net::HttpRequestHeaders* headers) {
+ return net::OK;
+}
+
+void ShellNetworkDelegate::OnSendHeaders(
+ net::URLRequest* request,
+ const net::HttpRequestHeaders& headers) {
+}
+
+int ShellNetworkDelegate::OnHeadersReceived(
+ net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
+ return net::OK;
+}
+
+void ShellNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
+ const GURL& new_location) {
+}
+
+void ShellNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
+}
+
+void ShellNetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
+ int bytes_read) {
+}
+
+void ShellNetworkDelegate::OnCompleted(net::URLRequest* request, bool started) {
+}
+
+void ShellNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) {
+}
+
+void ShellNetworkDelegate::OnPACScriptError(int line_number,
+ const string16& error) {
+}
+
+ShellNetworkDelegate::AuthRequiredResponse ShellNetworkDelegate::OnAuthRequired(
+ net::URLRequest* request,
+ const net::AuthChallengeInfo& auth_info,
+ const AuthCallback& callback,
+ net::AuthCredentials* credentials) {
+ return AUTH_REQUIRED_RESPONSE_NO_ACTION;
+}
+
+bool ShellNetworkDelegate::OnCanGetCookies(const net::URLRequest& request,
+ const net::CookieList& cookie_list) {
+ net::StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
+ net::StaticCookiePolicy::ALLOW_ALL_COOKIES :
+ net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
+ net::StaticCookiePolicy policy(policy_type);
+ int rv = policy.CanGetCookies(
+ request.url(), request.first_party_for_cookies());
+ return rv == net::OK;
+}
+
+bool ShellNetworkDelegate::OnCanSetCookie(const net::URLRequest& request,
+ const std::string& cookie_line,
+ net::CookieOptions* options) {
+ net::StaticCookiePolicy::Type policy_type = g_accept_all_cookies ?
+ net::StaticCookiePolicy::ALLOW_ALL_COOKIES :
+ net::StaticCookiePolicy::BLOCK_SETTING_THIRD_PARTY_COOKIES;
+ net::StaticCookiePolicy policy(policy_type);
+ int rv = policy.CanSetCookie(
+ request.url(), request.first_party_for_cookies());
+ return rv == net::OK;
+}
+
+bool ShellNetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
+ const base::FilePath& path) const {
+ return true;
+}
+
+bool ShellNetworkDelegate::OnCanThrottleRequest(
+ const net::URLRequest& request) const {
+ return false;
+}
+
+int ShellNetworkDelegate::OnBeforeSocketStreamConnect(
+ net::SocketStream* socket,
+ const net::CompletionCallback& callback) {
+ return net::OK;
+}
+
+void ShellNetworkDelegate::OnRequestWaitStateChange(
+ const net::URLRequest& request,
+ RequestWaitState waiting) {
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_network_delegate.h b/content/shell/browser/shell_network_delegate.h
new file mode 100644
index 0000000..a3ce0a2
--- /dev/null
+++ b/content/shell/browser/shell_network_delegate.h
@@ -0,0 +1,71 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "net/base/network_delegate.h"
+
+namespace content {
+
+class ShellNetworkDelegate : public net::NetworkDelegate {
+ public:
+ ShellNetworkDelegate();
+ virtual ~ShellNetworkDelegate();
+
+ static void SetAcceptAllCookies(bool accept);
+
+ private:
+ // net::NetworkDelegate implementation.
+ virtual int OnBeforeURLRequest(net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ GURL* new_url) OVERRIDE;
+ virtual int OnBeforeSendHeaders(net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ net::HttpRequestHeaders* headers) OVERRIDE;
+ virtual void OnSendHeaders(net::URLRequest* request,
+ const net::HttpRequestHeaders& headers) OVERRIDE;
+ virtual int OnHeadersReceived(
+ net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>*
+ override_response_headers) OVERRIDE;
+ virtual void OnBeforeRedirect(net::URLRequest* request,
+ const GURL& new_location) OVERRIDE;
+ virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE;
+ virtual void OnRawBytesRead(const net::URLRequest& request,
+ int bytes_read) OVERRIDE;
+ virtual void OnCompleted(net::URLRequest* request, bool started) OVERRIDE;
+ virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE;
+ virtual void OnPACScriptError(int line_number,
+ const string16& error) OVERRIDE;
+ virtual AuthRequiredResponse OnAuthRequired(
+ net::URLRequest* request,
+ const net::AuthChallengeInfo& auth_info,
+ const AuthCallback& callback,
+ net::AuthCredentials* credentials) OVERRIDE;
+ virtual bool OnCanGetCookies(const net::URLRequest& request,
+ const net::CookieList& cookie_list) OVERRIDE;
+ virtual bool OnCanSetCookie(const net::URLRequest& request,
+ const std::string& cookie_line,
+ net::CookieOptions* options) OVERRIDE;
+ virtual bool OnCanAccessFile(const net::URLRequest& request,
+ const base::FilePath& path) const OVERRIDE;
+ virtual bool OnCanThrottleRequest(
+ const net::URLRequest& request) const OVERRIDE;
+ virtual int OnBeforeSocketStreamConnect(
+ net::SocketStream* stream,
+ const net::CompletionCallback& callback) OVERRIDE;
+ virtual void OnRequestWaitStateChange(const net::URLRequest& request,
+ RequestWaitState state) OVERRIDE;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_
diff --git a/content/shell/browser/shell_plugin_service_filter.cc b/content/shell/browser/shell_plugin_service_filter.cc
new file mode 100644
index 0000000..d41b9bd
--- /dev/null
+++ b/content/shell/browser/shell_plugin_service_filter.cc
@@ -0,0 +1,31 @@
+// 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_plugin_service_filter.h"
+
+#include "base/strings/utf_string_conversions.h"
+#include "content/public/common/webplugininfo.h"
+
+namespace content {
+
+ShellPluginServiceFilter::ShellPluginServiceFilter() {}
+
+ShellPluginServiceFilter::~ShellPluginServiceFilter() {}
+
+bool ShellPluginServiceFilter::IsPluginAvailable(
+ int render_process_id,
+ int render_view_id,
+ const void* context,
+ const GURL& url,
+ const GURL& policy_url,
+ WebPluginInfo* plugin) {
+ return plugin->name == ASCIIToUTF16("WebKit Test PlugIn");
+}
+
+bool ShellPluginServiceFilter::CanLoadPlugin(int render_process_id,
+ const base::FilePath& path) {
+ return true;
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_plugin_service_filter.h b/content/shell/browser/shell_plugin_service_filter.h
new file mode 100644
index 0000000..3e9cb5d
--- /dev/null
+++ b/content/shell/browser/shell_plugin_service_filter.h
@@ -0,0 +1,37 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_PLUGIN_SERVICE_FILTER_H_
+#define CONTENT_SHELL_BROWSER_SHELL_PLUGIN_SERVICE_FILTER_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "content/public/browser/plugin_service_filter.h"
+
+namespace content {
+
+class ShellPluginServiceFilter : public PluginServiceFilter {
+ public:
+ ShellPluginServiceFilter();
+ virtual ~ShellPluginServiceFilter();
+
+ // PluginServiceFilter implementation.
+ virtual bool IsPluginAvailable(int render_process_id,
+ int render_view_id,
+ const void* context,
+ const GURL& url,
+ const GURL& policy_url,
+ WebPluginInfo* plugin) OVERRIDE;
+
+ virtual bool CanLoadPlugin(int render_process_id,
+ const base::FilePath& path) OVERRIDE;
+
+ private:
+
+ DISALLOW_COPY_AND_ASSIGN(ShellPluginServiceFilter);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_PLUGIN_SERVICE_FILTER_H_
diff --git a/content/shell/browser/shell_quota_permission_context.cc b/content/shell/browser/shell_quota_permission_context.cc
new file mode 100644
index 0000000..064322f
--- /dev/null
+++ b/content/shell/browser/shell_quota_permission_context.cc
@@ -0,0 +1,32 @@
+// 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_quota_permission_context.h"
+
+#include "webkit/common/quota/quota_types.h"
+
+namespace content {
+
+ShellQuotaPermissionContext::ShellQuotaPermissionContext() {}
+
+void ShellQuotaPermissionContext::RequestQuotaPermission(
+ const GURL& origin_url,
+ quota::StorageType type,
+ int64 requested_quota,
+ int render_process_id,
+ int render_view_id,
+ const PermissionCallback& callback) {
+ if (type != quota::kStorageTypePersistent) {
+ // For now we only support requesting quota with this interface
+ // for Persistent storage type.
+ callback.Run(QUOTA_PERMISSION_RESPONSE_DISALLOW);
+ return;
+ }
+
+ callback.Run(QUOTA_PERMISSION_RESPONSE_ALLOW);
+}
+
+ShellQuotaPermissionContext::~ShellQuotaPermissionContext() {}
+
+} // namespace content
diff --git a/content/shell/browser/shell_quota_permission_context.h b/content/shell/browser/shell_quota_permission_context.h
new file mode 100644
index 0000000..381338d
--- /dev/null
+++ b/content/shell/browser/shell_quota_permission_context.h
@@ -0,0 +1,34 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_QUOTA_PERMISSION_CONTEXT_H_
+#define CONTENT_SHELL_BROWSER_SHELL_QUOTA_PERMISSION_CONTEXT_H_
+
+#include "base/compiler_specific.h"
+#include "content/public/browser/quota_permission_context.h"
+
+namespace content {
+
+class ShellQuotaPermissionContext : public QuotaPermissionContext {
+ public:
+ ShellQuotaPermissionContext();
+
+ // The callback will be dispatched on the IO thread.
+ virtual void RequestQuotaPermission(
+ const GURL& origin_url,
+ quota::StorageType type,
+ int64 new_quota,
+ int render_process_id,
+ int render_view_id,
+ const PermissionCallback& callback) OVERRIDE;
+
+ private:
+ virtual ~ShellQuotaPermissionContext();
+
+ DISALLOW_COPY_AND_ASSIGN(ShellQuotaPermissionContext);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_QUOTA_PERMISSION_CONTEXT_H_
diff --git a/content/shell/browser/shell_resource_dispatcher_host_delegate.cc b/content/shell/browser/shell_resource_dispatcher_host_delegate.cc
new file mode 100644
index 0000000..d0994b1
--- /dev/null
+++ b/content/shell/browser/shell_resource_dispatcher_host_delegate.cc
@@ -0,0 +1,44 @@
+// 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_resource_dispatcher_host_delegate.h"
+
+#include "base/command_line.h"
+#include "content/shell/browser/shell_login_dialog.h"
+#include "content/shell/common/shell_switches.h"
+
+namespace content {
+
+ShellResourceDispatcherHostDelegate::ShellResourceDispatcherHostDelegate() {
+}
+
+ShellResourceDispatcherHostDelegate::~ShellResourceDispatcherHostDelegate() {
+}
+
+bool ShellResourceDispatcherHostDelegate::AcceptAuthRequest(
+ net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info) {
+ bool accept_auth_request =
+ !CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree);
+ return accept_auth_request;
+}
+
+ResourceDispatcherHostLoginDelegate*
+ShellResourceDispatcherHostDelegate::CreateLoginDelegate(
+ net::AuthChallengeInfo* auth_info, net::URLRequest* request) {
+ if (!login_request_callback_.is_null()) {
+ login_request_callback_.Run();
+ login_request_callback_.Reset();
+ return NULL;
+ }
+
+#if !defined(OS_MACOSX) && !defined(TOOLKIT_GTK)
+// TODO: implement ShellLoginDialog for other platforms, drop this #if
+ return NULL;
+#else
+ return new ShellLoginDialog(auth_info, request);
+#endif
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_resource_dispatcher_host_delegate.h b/content/shell/browser/shell_resource_dispatcher_host_delegate.h
new file mode 100644
index 0000000..90e6d4c
--- /dev/null
+++ b/content/shell/browser/shell_resource_dispatcher_host_delegate.h
@@ -0,0 +1,40 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
+
+#include "base/callback.h"
+#include "base/compiler_specific.h"
+#include "content/public/browser/resource_dispatcher_host_delegate.h"
+
+namespace content {
+
+class ShellResourceDispatcherHostDelegate
+ : public ResourceDispatcherHostDelegate {
+ public:
+ ShellResourceDispatcherHostDelegate();
+ virtual ~ShellResourceDispatcherHostDelegate();
+
+ // ResourceDispatcherHostDelegate implementation.
+ virtual bool AcceptAuthRequest(net::URLRequest* request,
+ net::AuthChallengeInfo* auth_info) OVERRIDE;
+ virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
+ net::AuthChallengeInfo* auth_info, net::URLRequest* request) OVERRIDE;
+
+ // Used for content_browsertests.
+ void set_login_request_callback(
+ base::Callback<void()> login_request_callback) {
+ login_request_callback_ = login_request_callback;
+ }
+
+ private:
+ base::Callback<void()> login_request_callback_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellResourceDispatcherHostDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_RESOURCE_DISPATCHER_HOST_DELEGATE_H_
diff --git a/content/shell/browser/shell_url_request_context_getter.cc b/content/shell/browser/shell_url_request_context_getter.cc
new file mode 100644
index 0000000..dfdb852
--- /dev/null
+++ b/content/shell/browser/shell_url_request_context_getter.cc
@@ -0,0 +1,231 @@
+// 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_url_request_context_getter.h"
+
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/string_split.h"
+#include "base/strings/string_util.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "base/threading/worker_pool.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/common/content_switches.h"
+#include "content/public/common/url_constants.h"
+#include "content/shell/browser/shell_network_delegate.h"
+#include "content/shell/common/shell_switches.h"
+#include "net/base/cache_type.h"
+#include "net/cert/cert_verifier.h"
+#include "net/cookies/cookie_monster.h"
+#include "net/dns/host_resolver.h"
+#include "net/dns/mapped_host_resolver.h"
+#include "net/http/http_auth_handler_factory.h"
+#include "net/http/http_cache.h"
+#include "net/http/http_network_session.h"
+#include "net/http/http_server_properties_impl.h"
+#include "net/http/transport_security_state.h"
+#include "net/proxy/proxy_service.h"
+#include "net/ssl/default_server_bound_cert_store.h"
+#include "net/ssl/server_bound_cert_service.h"
+#include "net/ssl/ssl_config_service_defaults.h"
+#include "net/url_request/data_protocol_handler.h"
+#include "net/url_request/file_protocol_handler.h"
+#include "net/url_request/protocol_intercept_job_factory.h"
+#include "net/url_request/static_http_user_agent_settings.h"
+#include "net/url_request/url_request_context.h"
+#include "net/url_request/url_request_context_storage.h"
+#include "net/url_request/url_request_job_factory_impl.h"
+
+namespace content {
+
+namespace {
+
+void InstallProtocolHandlers(net::URLRequestJobFactoryImpl* job_factory,
+ ProtocolHandlerMap* protocol_handlers) {
+ for (ProtocolHandlerMap::iterator it =
+ protocol_handlers->begin();
+ it != protocol_handlers->end();
+ ++it) {
+ bool set_protocol = job_factory->SetProtocolHandler(
+ it->first, it->second.release());
+ DCHECK(set_protocol);
+ }
+ protocol_handlers->clear();
+}
+
+} // namespace
+
+ShellURLRequestContextGetter::ShellURLRequestContextGetter(
+ bool ignore_certificate_errors,
+ const base::FilePath& base_path,
+ base::MessageLoop* io_loop,
+ base::MessageLoop* file_loop,
+ ProtocolHandlerMap* protocol_handlers,
+ net::NetLog* net_log)
+ : ignore_certificate_errors_(ignore_certificate_errors),
+ base_path_(base_path),
+ io_loop_(io_loop),
+ file_loop_(file_loop),
+ net_log_(net_log) {
+ // Must first be created on the UI thread.
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+
+ std::swap(protocol_handlers_, *protocol_handlers);
+
+ // We must create the proxy config service on the UI loop on Linux because it
+ // must synchronously run on the glib message loop. This will be passed to
+ // the URLRequestContextStorage on the IO thread in GetURLRequestContext().
+ if (!CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree)) {
+ proxy_config_service_.reset(
+ net::ProxyService::CreateSystemProxyConfigService(
+ io_loop_->message_loop_proxy().get(), file_loop_));
+ }
+}
+
+ShellURLRequestContextGetter::~ShellURLRequestContextGetter() {
+}
+
+net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
+
+ if (!url_request_context_) {
+ const CommandLine& command_line = *CommandLine::ForCurrentProcess();
+
+ url_request_context_.reset(new net::URLRequestContext());
+ url_request_context_->set_net_log(net_log_);
+ network_delegate_.reset(new ShellNetworkDelegate);
+ if (command_line.HasSwitch(switches::kDumpRenderTree))
+ ShellNetworkDelegate::SetAcceptAllCookies(false);
+ url_request_context_->set_network_delegate(network_delegate_.get());
+ storage_.reset(
+ new net::URLRequestContextStorage(url_request_context_.get()));
+ storage_->set_cookie_store(new net::CookieMonster(NULL, NULL));
+ storage_->set_server_bound_cert_service(new net::ServerBoundCertService(
+ new net::DefaultServerBoundCertStore(NULL),
+ base::WorkerPool::GetTaskRunner(true)));
+ storage_->set_http_user_agent_settings(
+ new net::StaticHttpUserAgentSettings("en-us,en", EmptyString()));
+
+ scoped_ptr<net::HostResolver> host_resolver(
+ net::HostResolver::CreateDefaultResolver(
+ url_request_context_->net_log()));
+
+ storage_->set_cert_verifier(net::CertVerifier::CreateDefault());
+ storage_->set_transport_security_state(new net::TransportSecurityState);
+ if (command_line.HasSwitch(switches::kDumpRenderTree)) {
+ storage_->set_proxy_service(net::ProxyService::CreateDirect());
+ } else {
+ // TODO(jam): use v8 if possible, look at chrome code.
+ storage_->set_proxy_service(
+ net::ProxyService::CreateUsingSystemProxyResolver(
+ proxy_config_service_.release(),
+ 0,
+ url_request_context_->net_log()));
+ }
+ storage_->set_ssl_config_service(new net::SSLConfigServiceDefaults);
+ storage_->set_http_auth_handler_factory(
+ net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
+ storage_->set_http_server_properties(
+ scoped_ptr<net::HttpServerProperties>(
+ new net::HttpServerPropertiesImpl()));
+
+ base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
+ net::HttpCache::DefaultBackend* main_backend =
+ new net::HttpCache::DefaultBackend(
+ net::DISK_CACHE,
+#if defined(OS_ANDROID)
+ // TODO(rdsmith): Remove when default backend for Android is
+ // changed to simple cache.
+ net::CACHE_BACKEND_SIMPLE,
+#else
+ net::CACHE_BACKEND_DEFAULT,
+#endif
+ cache_path,
+ 0,
+ BrowserThread::GetMessageLoopProxyForThread(BrowserThread::CACHE)
+ .get());
+
+ net::HttpNetworkSession::Params network_session_params;
+ network_session_params.cert_verifier =
+ url_request_context_->cert_verifier();
+ network_session_params.transport_security_state =
+ url_request_context_->transport_security_state();
+ network_session_params.server_bound_cert_service =
+ url_request_context_->server_bound_cert_service();
+ network_session_params.proxy_service =
+ url_request_context_->proxy_service();
+ network_session_params.ssl_config_service =
+ url_request_context_->ssl_config_service();
+ network_session_params.http_auth_handler_factory =
+ url_request_context_->http_auth_handler_factory();
+ network_session_params.network_delegate =
+ network_delegate_.get();
+ network_session_params.http_server_properties =
+ url_request_context_->http_server_properties();
+ network_session_params.net_log =
+ url_request_context_->net_log();
+ network_session_params.ignore_certificate_errors =
+ ignore_certificate_errors_;
+ if (command_line.HasSwitch(switches::kTestingFixedHttpPort)) {
+ int value;
+ base::StringToInt(command_line.GetSwitchValueASCII(
+ switches::kTestingFixedHttpPort), &value);
+ network_session_params.testing_fixed_http_port = value;
+ }
+ if (command_line.HasSwitch(switches::kTestingFixedHttpsPort)) {
+ int value;
+ base::StringToInt(command_line.GetSwitchValueASCII(
+ switches::kTestingFixedHttpsPort), &value);
+ network_session_params.testing_fixed_https_port = value;
+ }
+ if (command_line.HasSwitch(switches::kHostResolverRules)) {
+ scoped_ptr<net::MappedHostResolver> mapped_host_resolver(
+ new net::MappedHostResolver(host_resolver.Pass()));
+ mapped_host_resolver->SetRulesFromString(
+ command_line.GetSwitchValueASCII(switches::kHostResolverRules));
+ host_resolver = mapped_host_resolver.Pass();
+ }
+
+ // Give |storage_| ownership at the end in case it's |mapped_host_resolver|.
+ storage_->set_host_resolver(host_resolver.Pass());
+ network_session_params.host_resolver =
+ url_request_context_->host_resolver();
+
+ net::HttpCache* main_cache = new net::HttpCache(
+ network_session_params, main_backend);
+ storage_->set_http_transaction_factory(main_cache);
+
+ scoped_ptr<net::URLRequestJobFactoryImpl> job_factory(
+ new net::URLRequestJobFactoryImpl());
+ // Keep ProtocolHandlers added in sync with
+ // ShellContentBrowserClient::IsHandledURL().
+ InstallProtocolHandlers(job_factory.get(), &protocol_handlers_);
+ bool set_protocol = job_factory->SetProtocolHandler(
+ chrome::kDataScheme,
+ new net::DataProtocolHandler);
+ DCHECK(set_protocol);
+ set_protocol = job_factory->SetProtocolHandler(
+ chrome::kFileScheme,
+ new net::FileProtocolHandler(
+ content::BrowserThread::GetBlockingPool()->
+ GetTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)));
+ DCHECK(set_protocol);
+ storage_->set_job_factory(job_factory.release());
+ }
+
+ return url_request_context_.get();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ ShellURLRequestContextGetter::GetNetworkTaskRunner() const {
+ return BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO);
+}
+
+net::HostResolver* ShellURLRequestContextGetter::host_resolver() {
+ return url_request_context_->host_resolver();
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_url_request_context_getter.h b/content/shell/browser/shell_url_request_context_getter.h
new file mode 100644
index 0000000..b18c0a9
--- /dev/null
+++ b/content/shell/browser/shell_url_request_context_getter.h
@@ -0,0 +1,69 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
+#define CONTENT_SHELL_BROWSER_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
+
+#include "base/compiler_specific.h"
+#include "base/files/file_path.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/browser/content_browser_client.h"
+#include "net/url_request/url_request_context_getter.h"
+#include "net/url_request/url_request_job_factory.h"
+
+namespace base {
+class MessageLoop;
+}
+
+namespace net {
+class HostResolver;
+class MappedHostResolver;
+class NetworkDelegate;
+class NetLog;
+class ProxyConfigService;
+class URLRequestContextStorage;
+}
+
+namespace content {
+
+class ShellURLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+ ShellURLRequestContextGetter(
+ bool ignore_certificate_errors,
+ const base::FilePath& base_path,
+ base::MessageLoop* io_loop,
+ base::MessageLoop* file_loop,
+ ProtocolHandlerMap* protocol_handlers,
+ net::NetLog* net_log);
+
+ // net::URLRequestContextGetter implementation.
+ virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE;
+ virtual scoped_refptr<base::SingleThreadTaskRunner>
+ GetNetworkTaskRunner() const OVERRIDE;
+
+ net::HostResolver* host_resolver();
+
+ protected:
+ virtual ~ShellURLRequestContextGetter();
+
+ private:
+ bool ignore_certificate_errors_;
+ base::FilePath base_path_;
+ base::MessageLoop* io_loop_;
+ base::MessageLoop* file_loop_;
+ net::NetLog* net_log_;
+
+ scoped_ptr<net::ProxyConfigService> proxy_config_service_;
+ scoped_ptr<net::NetworkDelegate> network_delegate_;
+ scoped_ptr<net::URLRequestContextStorage> storage_;
+ scoped_ptr<net::URLRequestContext> url_request_context_;
+ ProtocolHandlerMap protocol_handlers_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellURLRequestContextGetter);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
diff --git a/content/shell/browser/shell_web_contents_view_delegate.h b/content/shell/browser/shell_web_contents_view_delegate.h
new file mode 100644
index 0000000..86d97b4
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate.h
@@ -0,0 +1,83 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
+#define CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
+
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view_delegate.h"
+#include "content/public/common/context_menu_params.h"
+
+#if defined(TOOLKIT_GTK)
+#include "ui/base/gtk/gtk_signal.h"
+#include "ui/base/gtk/owned_widget_gtk.h"
+#endif
+
+namespace content {
+
+class ShellWebContentsViewDelegate : public WebContentsViewDelegate {
+ public:
+ explicit ShellWebContentsViewDelegate(WebContents* web_contents);
+ virtual ~ShellWebContentsViewDelegate();
+
+ // Overridden from WebContentsViewDelegate:
+ virtual void ShowContextMenu(const ContextMenuParams& params) OVERRIDE;
+ virtual WebDragDestDelegate* GetDragDestDelegate() OVERRIDE;
+
+#if defined(TOOLKIT_GTK)
+ virtual void Initialize(GtkWidget* expanded_container,
+ ui::FocusStoreGtk* focus_store) OVERRIDE;
+ virtual gfx::NativeView GetNativeView() const OVERRIDE;
+ virtual void Focus() OVERRIDE;
+ virtual gboolean OnNativeViewFocusEvent(GtkWidget* widget,
+ GtkDirectionType type,
+ gboolean* return_value) OVERRIDE;
+#elif defined(OS_MACOSX)
+ virtual NSObject<RenderWidgetHostViewMacDelegate>*
+ CreateRenderWidgetHostViewDelegate(
+ RenderWidgetHost* render_widget_host) OVERRIDE;
+ void ActionPerformed(int id);
+#elif defined(OS_WIN)
+ virtual void StoreFocus() OVERRIDE;
+ virtual void RestoreFocus() OVERRIDE;
+ virtual bool Focus() OVERRIDE;
+ virtual void TakeFocus(bool reverse) OVERRIDE;
+ virtual void SizeChanged(const gfx::Size& size) OVERRIDE;
+ void MenuItemSelected(int selection);
+#endif
+
+ private:
+ WebContents* web_contents_;
+ ContextMenuParams params_;
+
+#if defined(TOOLKIT_GTK)
+ ui::OwnedWidgetGtk floating_;
+ GtkWidget* expanded_container_;
+
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnBackMenuActivated);
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnForwardMenuActivated);
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnReloadMenuActivated);
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnOpenURLMenuActivated);
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnCutMenuActivated);
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnCopyMenuActivated);
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnPasteMenuActivated);
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnDeleteMenuActivated);
+ CHROMEGTK_CALLBACK_0(ShellWebContentsViewDelegate, void,
+ OnInspectMenuActivated);
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(ShellWebContentsViewDelegate);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_H_
diff --git a/content/shell/browser/shell_web_contents_view_delegate_android.cc b/content/shell/browser/shell_web_contents_view_delegate_android.cc
new file mode 100644
index 0000000..3da5475
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_android.cc
@@ -0,0 +1,46 @@
+// 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_web_contents_view_delegate.h"
+
+#include "base/command_line.h"
+#include "content/public/browser/android/content_view_core.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/context_menu_params.h"
+#include "content/shell/browser/shell_web_contents_view_delegate_creator.h"
+
+namespace content {
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+ WebContents* web_contents) {
+ return new ShellWebContentsViewDelegate(web_contents);
+}
+
+
+ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
+ WebContents* web_contents)
+ : web_contents_(web_contents) {
+}
+
+ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
+}
+
+void ShellWebContentsViewDelegate::ShowContextMenu(
+ const ContextMenuParams& params) {
+ if (params.is_editable && params.selection_text.empty()) {
+ content::ContentViewCore* content_view_core =
+ ContentViewCore::FromWebContents(web_contents_);
+ if (content_view_core) {
+ content_view_core->ShowPastePopup(params.selection_start.x(),
+ params.selection_start.y());
+ }
+ }
+}
+
+WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
+ return NULL;
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_web_contents_view_delegate_creator.h b/content/shell/browser/shell_web_contents_view_delegate_creator.h
new file mode 100644
index 0000000..819ce1e
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_creator.h
@@ -0,0 +1,18 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
+#define CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
+
+namespace content {
+
+class WebContents;
+class WebContentsViewDelegate;
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+ WebContents* web_contents);
+
+} // namespace content
+
+#endif //CONTENT_SHELL_BROWSER_SHELL_WEB_CONTENTS_VIEW_DELEGATE_CREATOR_H_
diff --git a/content/shell/browser/shell_web_contents_view_delegate_gtk.cc b/content/shell/browser/shell_web_contents_view_delegate_gtk.cc
new file mode 100644
index 0000000..4c98257
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_gtk.cc
@@ -0,0 +1,241 @@
+// 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_web_contents_view_delegate.h"
+
+#include "base/command_line.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/context_menu_params.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.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_web_contents_view_delegate_creator.h"
+#include "content/shell/common/shell_switches.h"
+#include "third_party/WebKit/public/web/WebContextMenuData.h"
+#include "ui/base/gtk/focus_store_gtk.h"
+#include "ui/base/gtk/gtk_floating_container.h"
+
+using WebKit::WebContextMenuData;
+
+namespace content {
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+ WebContents* web_contents) {
+ return new ShellWebContentsViewDelegate(web_contents);
+}
+
+ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
+ WebContents* web_contents)
+ : web_contents_(web_contents),
+ floating_(gtk_floating_container_new()) {
+}
+
+ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
+ floating_.Destroy();
+}
+
+void ShellWebContentsViewDelegate::ShowContextMenu(
+ const ContextMenuParams& params) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+
+ GtkWidget* menu = gtk_menu_new();
+
+ params_ = params;
+ bool has_link = !params_.unfiltered_link_url.is_empty();
+ bool has_selection = !params_.selection_text.empty();
+
+ if (params_.media_type == WebContextMenuData::MediaTypeNone &&
+ !has_link &&
+ !has_selection &&
+ !params_.is_editable) {
+ GtkWidget* back_menu = gtk_menu_item_new_with_label("Back");
+ gtk_menu_append(GTK_MENU(menu), back_menu);
+ g_signal_connect(back_menu,
+ "activate",
+ G_CALLBACK(OnBackMenuActivatedThunk),
+ this);
+ gtk_widget_set_sensitive(back_menu,
+ web_contents_->GetController().CanGoBack());
+
+ GtkWidget* forward_menu = gtk_menu_item_new_with_label("Forward");
+ gtk_menu_append(GTK_MENU(menu), forward_menu);
+ g_signal_connect(forward_menu,
+ "activate",
+ G_CALLBACK(OnForwardMenuActivatedThunk),
+ this);
+ gtk_widget_set_sensitive(forward_menu,
+ web_contents_->GetController().CanGoForward());
+
+ GtkWidget* reload_menu = gtk_menu_item_new_with_label("Reload");
+ gtk_menu_append(GTK_MENU(menu), reload_menu);
+ g_signal_connect(reload_menu,
+ "activate",
+ G_CALLBACK(OnReloadMenuActivatedThunk),
+ this);
+
+ GtkWidget* navigate_separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(menu), navigate_separator);
+ }
+
+ if (has_link) {
+ GtkWidget* open_menu = gtk_menu_item_new_with_label("Open in New Window");
+ gtk_menu_append(GTK_MENU(menu), open_menu);
+ g_signal_connect(open_menu,
+ "activate",
+ G_CALLBACK(OnOpenURLMenuActivatedThunk),
+ this);
+
+ GtkWidget* link_separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(menu), link_separator);
+ }
+
+ if (params_.is_editable) {
+ GtkWidget* cut_menu = gtk_menu_item_new_with_label("Cut");
+ gtk_menu_append(GTK_MENU(menu), cut_menu);
+ g_signal_connect(cut_menu,
+ "activate",
+ G_CALLBACK(OnCutMenuActivatedThunk),
+ this);
+ gtk_widget_set_sensitive(
+ cut_menu,
+ params_.edit_flags & WebContextMenuData::CanCut);
+
+ GtkWidget* copy_menu = gtk_menu_item_new_with_label("Copy");
+ gtk_menu_append(GTK_MENU(menu), copy_menu);
+ g_signal_connect(copy_menu,
+ "activate",
+ G_CALLBACK(OnCopyMenuActivatedThunk),
+ this);
+ gtk_widget_set_sensitive(
+ copy_menu,
+ params_.edit_flags & WebContextMenuData::CanCopy);
+
+ GtkWidget* paste_menu = gtk_menu_item_new_with_label("Paste");
+ gtk_menu_append(GTK_MENU(menu), paste_menu);
+ g_signal_connect(paste_menu,
+ "activate",
+ G_CALLBACK(OnPasteMenuActivatedThunk),
+ this);
+ gtk_widget_set_sensitive(
+ paste_menu,
+ params_.edit_flags & WebContextMenuData::CanPaste);
+
+ GtkWidget* delete_menu = gtk_menu_item_new_with_label("Delete");
+ gtk_menu_append(GTK_MENU(menu), delete_menu);
+ g_signal_connect(delete_menu,
+ "activate",
+ G_CALLBACK(OnDeleteMenuActivatedThunk),
+ this);
+ gtk_widget_set_sensitive(
+ delete_menu,
+ params_.edit_flags & WebContextMenuData::CanDelete);
+
+ GtkWidget* edit_separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(menu), edit_separator);
+ } else if (has_selection) {
+ GtkWidget* copy_menu = gtk_menu_item_new_with_label("Copy");
+ gtk_menu_append(GTK_MENU(menu), copy_menu);
+ g_signal_connect(copy_menu,
+ "activate",
+ G_CALLBACK(OnCopyMenuActivatedThunk),
+ this);
+
+ GtkWidget* copy_separator = gtk_separator_menu_item_new();
+ gtk_menu_append(GTK_MENU(menu), copy_separator);
+ }
+
+ GtkWidget* inspect_menu = gtk_menu_item_new_with_label("Inspect...");
+ gtk_menu_append(GTK_MENU(menu), inspect_menu);
+ g_signal_connect(inspect_menu,
+ "activate",
+ G_CALLBACK(OnInspectMenuActivatedThunk),
+ this);
+
+ gtk_widget_show_all(menu);
+
+ gtk_menu_popup(GTK_MENU(menu), NULL, NULL, NULL, NULL, 3, GDK_CURRENT_TIME);
+}
+
+WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
+ return NULL;
+}
+
+void ShellWebContentsViewDelegate::Initialize(GtkWidget* expanded_container,
+ ui::FocusStoreGtk* focus_store) {
+ expanded_container_ = expanded_container;
+
+ gtk_container_add(GTK_CONTAINER(floating_.get()), expanded_container_);
+ gtk_widget_show(floating_.get());
+}
+
+gfx::NativeView ShellWebContentsViewDelegate::GetNativeView() const {
+ return floating_.get();
+}
+
+void ShellWebContentsViewDelegate::Focus() {
+ GtkWidget* widget = web_contents_->GetView()->GetContentNativeView();
+ if (widget)
+ gtk_widget_grab_focus(widget);
+}
+
+gboolean ShellWebContentsViewDelegate::OnNativeViewFocusEvent(
+ GtkWidget* widget,
+ GtkDirectionType type,
+ gboolean* return_value) {
+ return false;
+}
+
+void ShellWebContentsViewDelegate::OnBackMenuActivated(GtkWidget* widget) {
+ web_contents_->GetController().GoToOffset(-1);
+ web_contents_->GetView()->Focus();
+}
+
+void ShellWebContentsViewDelegate::OnForwardMenuActivated(GtkWidget* widget) {
+ web_contents_->GetController().GoToOffset(1);
+ web_contents_->GetView()->Focus();
+}
+
+void ShellWebContentsViewDelegate::OnReloadMenuActivated(GtkWidget* widget) {
+ web_contents_->GetController().Reload(false);
+ web_contents_->GetView()->Focus();
+}
+
+void ShellWebContentsViewDelegate::OnOpenURLMenuActivated(GtkWidget* widget) {
+ ShellBrowserContext* browser_context =
+ ShellContentBrowserClient::Get()->browser_context();
+ Shell::CreateNewWindow(browser_context,
+ params_.link_url,
+ NULL,
+ MSG_ROUTING_NONE,
+ gfx::Size());
+}
+
+void ShellWebContentsViewDelegate::OnCutMenuActivated(GtkWidget* widget) {
+ web_contents_->GetRenderViewHost()->Cut();
+}
+
+void ShellWebContentsViewDelegate::OnCopyMenuActivated(GtkWidget* widget) {
+ web_contents_->GetRenderViewHost()->Copy();
+}
+
+void ShellWebContentsViewDelegate::OnPasteMenuActivated(GtkWidget* widget) {
+ web_contents_->GetRenderViewHost()->Paste();
+}
+
+void ShellWebContentsViewDelegate::OnDeleteMenuActivated(GtkWidget* widget) {
+ web_contents_->GetRenderViewHost()->Delete();
+}
+
+void ShellWebContentsViewDelegate::OnInspectMenuActivated(GtkWidget* widget) {
+ ShellDevToolsFrontend::Show(web_contents_);
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_web_contents_view_delegate_mac.mm b/content/shell/browser/shell_web_contents_view_delegate_mac.mm
new file mode 100644
index 0000000..00196af
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_mac.mm
@@ -0,0 +1,277 @@
+// 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_web_contents_view_delegate.h"
+
+#import <Cocoa/Cocoa.h>
+
+#include "base/command_line.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/context_menu_params.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.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_web_contents_view_delegate_creator.h"
+#include "content/shell/common/shell_switches.h"
+#include "third_party/WebKit/public/web/WebContextMenuData.h"
+
+using WebKit::WebContextMenuData;
+
+enum {
+ ShellContextMenuItemCutTag = 0,
+ ShellContextMenuItemCopyTag,
+ ShellContextMenuItemPasteTag,
+ ShellContextMenuItemDeleteTag,
+ ShellContextMenuItemOpenLinkTag,
+ ShellContextMenuItemBackTag,
+ ShellContextMenuItemForwardTag,
+ ShellContextMenuItemReloadTag,
+ ShellContextMenuItemInspectTag
+};
+
+@interface ShellContextMenuDelegate : NSObject<NSMenuDelegate> {
+ @private
+ content::ShellWebContentsViewDelegate* delegate_;
+}
+@end
+
+@implementation ShellContextMenuDelegate
+- (id)initWithDelegate:(content::ShellWebContentsViewDelegate*) delegate {
+ if ((self = [super init])) {
+ delegate_ = delegate;
+ }
+ return self;
+}
+
+- (void)itemSelected:(id)sender {
+ NSInteger tag = [sender tag];
+ delegate_->ActionPerformed(tag);
+}
+@end
+
+namespace {
+
+NSMenuItem* MakeContextMenuItem(NSString* title,
+ NSInteger tag,
+ NSMenu* menu,
+ BOOL enabled,
+ ShellContextMenuDelegate* delegate) {
+ NSMenuItem* menu_item =
+ [[NSMenuItem alloc] initWithTitle:title
+ action:@selector(itemSelected:)
+ keyEquivalent:@""];
+ [menu_item setTarget:delegate];
+ [menu_item setTag:tag];
+ [menu_item setEnabled:enabled];
+ [menu addItem:menu_item];
+
+ return menu_item;
+}
+
+} // namespace
+
+namespace content {
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+ WebContents* web_contents) {
+ return new ShellWebContentsViewDelegate(web_contents);
+}
+
+ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
+ WebContents* web_contents)
+ : web_contents_(web_contents) {
+}
+
+ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
+}
+
+void ShellWebContentsViewDelegate::ShowContextMenu(
+ const ContextMenuParams& params) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+
+ params_ = params;
+ bool has_link = !params_.unfiltered_link_url.is_empty();
+ bool has_selection = ! params_.selection_text.empty();
+
+ NSMenu* menu = [[[NSMenu alloc] initWithTitle:@""] autorelease];
+ ShellContextMenuDelegate* delegate =
+ [[ShellContextMenuDelegate alloc] initWithDelegate:this];
+ [menu setDelegate:delegate];
+ [menu setAutoenablesItems:NO];
+
+ if (params.media_type == WebContextMenuData::MediaTypeNone &&
+ !has_link &&
+ !has_selection &&
+ !params_.is_editable) {
+ BOOL back_menu_enabled =
+ web_contents_->GetController().CanGoBack() ? YES : NO;
+ MakeContextMenuItem(@"Back",
+ ShellContextMenuItemBackTag,
+ menu,
+ back_menu_enabled,
+ delegate);
+
+ BOOL forward_menu_enabled =
+ web_contents_->GetController().CanGoForward() ? YES : NO;
+ MakeContextMenuItem(@"Forward",
+ ShellContextMenuItemForwardTag,
+ menu,
+ forward_menu_enabled,
+ delegate);
+
+ MakeContextMenuItem(@"Reload",
+ ShellContextMenuItemReloadTag,
+ menu,
+ YES,
+ delegate);
+
+ NSMenuItem* separator = [NSMenuItem separatorItem];
+ [menu addItem:separator];
+ }
+
+ if (has_link) {
+ MakeContextMenuItem(@"Open In New Window",
+ ShellContextMenuItemOpenLinkTag,
+ menu,
+ YES,
+ delegate);
+
+ NSMenuItem* separator = [NSMenuItem separatorItem];
+ [menu addItem:separator];
+ }
+
+ if (params_.is_editable) {
+ BOOL cut_menu_enabled =
+ (params_.edit_flags & WebContextMenuData::CanCut) ? YES : NO;
+ MakeContextMenuItem(@"Cut",
+ ShellContextMenuItemCutTag,
+ menu,
+ cut_menu_enabled,
+ delegate);
+
+ BOOL copy_menu_enabled =
+ (params_.edit_flags & WebContextMenuData::CanCopy) ? YES : NO;
+ MakeContextMenuItem(@"Copy",
+ ShellContextMenuItemCopyTag,
+ menu,
+ copy_menu_enabled,
+ delegate);
+
+ BOOL paste_menu_enabled =
+ (params_.edit_flags & WebContextMenuData::CanPaste) ? YES : NO;
+ MakeContextMenuItem(@"Paste",
+ ShellContextMenuItemPasteTag,
+ menu,
+ paste_menu_enabled,
+ delegate);
+
+ BOOL delete_menu_enabled =
+ (params_.edit_flags & WebContextMenuData::CanDelete) ? YES : NO;
+ MakeContextMenuItem(@"Delete",
+ ShellContextMenuItemDeleteTag,
+ menu,
+ delete_menu_enabled,
+ delegate);
+
+ NSMenuItem* separator = [NSMenuItem separatorItem];
+ [menu addItem:separator];
+ } else if (has_selection) {
+ MakeContextMenuItem(@"Copy",
+ ShellContextMenuItemCopyTag,
+ menu,
+ YES,
+ delegate);
+
+ NSMenuItem* separator = [NSMenuItem separatorItem];
+ [menu addItem:separator];
+ }
+
+ MakeContextMenuItem(@"Inspect",
+ ShellContextMenuItemInspectTag,
+ menu,
+ YES,
+ delegate);
+
+ NSView* parent_view = web_contents_->GetView()->GetContentNativeView();
+ NSEvent* currentEvent = [NSApp currentEvent];
+ NSWindow* window = [parent_view window];
+ NSPoint position = [window mouseLocationOutsideOfEventStream];
+ NSTimeInterval eventTime = [currentEvent timestamp];
+ NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown
+ location:position
+ modifierFlags:NSRightMouseDownMask
+ timestamp:eventTime
+ windowNumber:[window windowNumber]
+ context:nil
+ eventNumber:0
+ clickCount:1
+ pressure:1.0];
+
+ [NSMenu popUpContextMenu:menu
+ withEvent:clickEvent
+ forView:parent_view];
+}
+
+void ShellWebContentsViewDelegate::ActionPerformed(int tag) {
+ switch (tag) {
+ case ShellContextMenuItemCutTag:
+ web_contents_->GetRenderViewHost()->Cut();
+ break;
+ case ShellContextMenuItemCopyTag:
+ web_contents_->GetRenderViewHost()->Copy();
+ break;
+ case ShellContextMenuItemPasteTag:
+ web_contents_->GetRenderViewHost()->Paste();
+ break;
+ case ShellContextMenuItemDeleteTag:
+ web_contents_->GetRenderViewHost()->Delete();
+ break;
+ case ShellContextMenuItemOpenLinkTag: {
+ ShellBrowserContext* browser_context =
+ ShellContentBrowserClient::Get()->browser_context();
+ Shell::CreateNewWindow(browser_context,
+ params_.link_url,
+ NULL,
+ MSG_ROUTING_NONE,
+ gfx::Size());
+ break;
+ }
+ case ShellContextMenuItemBackTag:
+ web_contents_->GetController().GoToOffset(-1);
+ web_contents_->GetView()->Focus();
+ break;
+ case ShellContextMenuItemForwardTag:
+ web_contents_->GetController().GoToOffset(1);
+ web_contents_->GetView()->Focus();
+ break;
+ case ShellContextMenuItemReloadTag: {
+ web_contents_->GetController().Reload(false);
+ web_contents_->GetView()->Focus();
+ break;
+ }
+ case ShellContextMenuItemInspectTag: {
+ ShellDevToolsFrontend::Show(web_contents_);
+ break;
+ }
+ }
+}
+
+WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
+ return NULL;
+}
+
+NSObject<RenderWidgetHostViewMacDelegate>*
+ShellWebContentsViewDelegate::CreateRenderWidgetHostViewDelegate(
+ content::RenderWidgetHost* render_widget_host) {
+ return NULL;
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_web_contents_view_delegate_win.cc b/content/shell/browser/shell_web_contents_view_delegate_win.cc
new file mode 100644
index 0000000..cd387f0
--- /dev/null
+++ b/content/shell/browser/shell_web_contents_view_delegate_win.cc
@@ -0,0 +1,254 @@
+// 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_web_contents_view_delegate.h"
+
+#include "base/command_line.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/context_menu_params.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.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_web_contents_view_delegate_creator.h"
+#include "content/shell/common/shell_switches.h"
+#include "third_party/WebKit/public/web/WebContextMenuData.h"
+
+using WebKit::WebContextMenuData;
+
+namespace {
+
+enum {
+ ShellContextMenuItemCutId = 10001,
+ ShellContextMenuItemCopyId,
+ ShellContextMenuItemPasteId,
+ ShellContextMenuItemDeleteId,
+ ShellContextMenuItemOpenLinkId,
+ ShellContextMenuItemBackId,
+ ShellContextMenuItemForwardId,
+ ShellContextMenuItemReloadId,
+ ShellContextMenuItemInspectId
+};
+
+void MakeContextMenuItem(HMENU menu,
+ int menu_index,
+ LPTSTR text,
+ UINT id,
+ bool enabled) {
+ MENUITEMINFO mii = {0};
+ mii.cbSize = sizeof(mii);
+ mii.fMask = MIIM_FTYPE | MIIM_ID | MIIM_DATA | MIIM_STRING | MIIM_STATE;
+ mii.fState = enabled ? MFS_ENABLED : (MF_DISABLED | MFS_GRAYED);
+ mii.fType = MFT_STRING;
+ mii.wID = id;
+ mii.dwTypeData = text;
+
+ InsertMenuItem(menu, menu_index, TRUE, &mii);
+}
+
+} // namespace
+
+namespace content {
+
+WebContentsViewDelegate* CreateShellWebContentsViewDelegate(
+ WebContents* web_contents) {
+ return new ShellWebContentsViewDelegate(web_contents);
+}
+
+ShellWebContentsViewDelegate::ShellWebContentsViewDelegate(
+ WebContents* web_contents)
+ : web_contents_(web_contents) {
+}
+
+ShellWebContentsViewDelegate::~ShellWebContentsViewDelegate() {
+}
+
+void ShellWebContentsViewDelegate::ShowContextMenu(
+ const ContextMenuParams& params) {
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDumpRenderTree))
+ return;
+
+ params_ = params;
+ bool has_link = !params_.unfiltered_link_url.is_empty();
+ bool has_selection = !params_.selection_text.empty();
+
+ HMENU menu = CreateMenu();
+ HMENU sub_menu = CreatePopupMenu();
+ AppendMenu(menu, MF_STRING | MF_POPUP, (UINT)sub_menu, L"");
+
+ int index = 0;
+ if (params_.media_type == WebContextMenuData::MediaTypeNone &&
+ !has_link &&
+ !has_selection &&
+ !params_.is_editable) {
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Back",
+ ShellContextMenuItemBackId,
+ web_contents_->GetController().CanGoBack());
+
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Forward",
+ ShellContextMenuItemForwardId,
+ web_contents_->GetController().CanGoForward());
+
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Reload",
+ ShellContextMenuItemReloadId,
+ true);
+
+ AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
+ index++;
+ }
+
+ if (has_link) {
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Open in New Window",
+ ShellContextMenuItemOpenLinkId,
+ true);
+ AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
+ index++;
+ }
+
+ if (params_.is_editable) {
+ bool cut_enabled = ((params_.edit_flags & WebContextMenuData::CanCut) != 0);
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Cut",
+ ShellContextMenuItemCutId,
+ cut_enabled);
+
+ bool copy_enabled =
+ ((params_.edit_flags & WebContextMenuData::CanCopy) != 0);
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Copy",
+ ShellContextMenuItemCopyId,
+ copy_enabled);
+
+ bool paste_enabled =
+ ((params_.edit_flags & WebContextMenuData::CanPaste) != 0);
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Paste",
+ ShellContextMenuItemPasteId,
+ paste_enabled);
+ bool delete_enabled =
+ ((params_.edit_flags & WebContextMenuData::CanDelete) != 0);
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Delete",
+ ShellContextMenuItemDeleteId,
+ delete_enabled);
+
+ AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
+ index++;
+ } else if (has_selection) {
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Copy",
+ ShellContextMenuItemCopyId,
+ true);
+
+ AppendMenu(sub_menu, MF_SEPARATOR, 0, NULL);
+ index++;
+ }
+
+ MakeContextMenuItem(sub_menu,
+ index++,
+ L"Inspect...",
+ ShellContextMenuItemInspectId,
+ true);
+#if defined(USE_AURA)
+ NOTIMPLEMENTED();
+#else
+ gfx::Point screen_point(params.x, params.y);
+ POINT point = screen_point.ToPOINT();
+ ClientToScreen(web_contents_->GetView()->GetNativeView(), &point);
+
+ int selection =
+ TrackPopupMenu(sub_menu,
+ TPM_LEFTALIGN | TPM_RIGHTBUTTON | TPM_RETURNCMD,
+ point.x, point.y,
+ 0,
+ web_contents_->GetView()->GetContentNativeView(),
+ NULL);
+
+ MenuItemSelected(selection);
+#endif
+ DestroyMenu(menu);
+}
+
+void ShellWebContentsViewDelegate::MenuItemSelected(int selection) {
+ switch (selection) {
+ case ShellContextMenuItemCutId:
+ web_contents_->GetRenderViewHost()->Cut();
+ break;
+ case ShellContextMenuItemCopyId:
+ web_contents_->GetRenderViewHost()->Copy();
+ break;
+ case ShellContextMenuItemPasteId:
+ web_contents_->GetRenderViewHost()->Paste();
+ break;
+ case ShellContextMenuItemDeleteId:
+ web_contents_->GetRenderViewHost()->Delete();
+ break;
+ case ShellContextMenuItemOpenLinkId: {
+ ShellBrowserContext* browser_context =
+ ShellContentBrowserClient::Get()->browser_context();
+ Shell::CreateNewWindow(browser_context,
+ params_.link_url,
+ NULL,
+ MSG_ROUTING_NONE,
+ gfx::Size());
+ break;
+ }
+ case ShellContextMenuItemBackId:
+ web_contents_->GetController().GoToOffset(-1);
+ web_contents_->GetView()->Focus();
+ break;
+ case ShellContextMenuItemForwardId:
+ web_contents_->GetController().GoToOffset(1);
+ web_contents_->GetView()->Focus();
+ break;
+ case ShellContextMenuItemReloadId:
+ web_contents_->GetController().Reload(false);
+ web_contents_->GetView()->Focus();
+ break;
+ case ShellContextMenuItemInspectId: {
+ ShellDevToolsFrontend::Show(web_contents_);
+ break;
+ }
+ }
+}
+
+WebDragDestDelegate* ShellWebContentsViewDelegate::GetDragDestDelegate() {
+ return NULL;
+}
+
+void ShellWebContentsViewDelegate::StoreFocus() {
+}
+
+void ShellWebContentsViewDelegate::RestoreFocus() {
+}
+
+bool ShellWebContentsViewDelegate::Focus() {
+ return false;
+}
+
+void ShellWebContentsViewDelegate::TakeFocus(bool reverse) {
+}
+
+void ShellWebContentsViewDelegate::SizeChanged(const gfx::Size& size) {
+}
+
+} // namespace content
diff --git a/content/shell/browser/shell_win.cc b/content/shell/browser/shell_win.cc
new file mode 100644
index 0000000..d1bb402
--- /dev/null
+++ b/content/shell/browser/shell_win.cc
@@ -0,0 +1,285 @@
+// 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 <windows.h>
+#include <commctrl.h>
+#include <fcntl.h>
+#include <io.h>
+
+#include "base/strings/utf_string_conversions.h"
+#include "base/win/wrapped_window_proc.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/shell/app/resource.h"
+#include "ui/base/win/hwnd_util.h"
+
+namespace {
+
+const wchar_t kWindowTitle[] = L"Content Shell";
+const wchar_t kWindowClass[] = L"CONTENT_SHELL";
+
+const int kButtonWidth = 72;
+const int kURLBarHeight = 24;
+
+const int kMaxURLLength = 1024;
+
+} // namespace
+
+namespace content {
+
+HINSTANCE Shell::instance_handle_;
+
+void Shell::PlatformInitialize(const gfx::Size& default_window_size) {
+ _setmode(_fileno(stdout), _O_BINARY);
+ _setmode(_fileno(stderr), _O_BINARY);
+ INITCOMMONCONTROLSEX InitCtrlEx;
+ InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ InitCtrlEx.dwICC = ICC_STANDARD_CLASSES;
+ InitCommonControlsEx(&InitCtrlEx);
+ RegisterWindowClass();
+}
+
+void Shell::PlatformExit() {
+ std::vector<Shell*> windows = windows_;
+ for (std::vector<Shell*>::iterator it = windows.begin();
+ it != windows.end(); ++it)
+ DestroyWindow((*it)->window_);
+}
+
+void Shell::PlatformCleanUp() {
+ // When the window is destroyed, tell the Edit field to forget about us,
+ // otherwise we will crash.
+ ui::SetWindowProc(url_edit_view_, default_edit_wnd_proc_);
+ ui::SetWindowUserData(url_edit_view_, NULL);
+}
+
+void Shell::PlatformEnableUIControl(UIControl control, bool is_enabled) {
+ int id;
+ switch (control) {
+ case BACK_BUTTON:
+ id = IDC_NAV_BACK;
+ break;
+ case FORWARD_BUTTON:
+ id = IDC_NAV_FORWARD;
+ break;
+ case STOP_BUTTON:
+ id = IDC_NAV_STOP;
+ break;
+ default:
+ NOTREACHED() << "Unknown UI control";
+ return;
+ }
+ EnableWindow(GetDlgItem(window_, id), is_enabled);
+}
+
+void Shell::PlatformSetAddressBarURL(const GURL& url) {
+ std::wstring url_string = UTF8ToWide(url.spec());
+ SendMessage(url_edit_view_, WM_SETTEXT, 0,
+ reinterpret_cast<LPARAM>(url_string.c_str()));
+}
+
+void Shell::PlatformSetIsLoading(bool loading) {
+}
+
+void Shell::PlatformCreateWindow(int width, int height) {
+ window_ = CreateWindow(kWindowClass, kWindowTitle,
+ WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0,
+ NULL, NULL, instance_handle_, NULL);
+ ui::SetWindowUserData(window_, this);
+
+ HWND hwnd;
+ int x = 0;
+
+ hwnd = CreateWindow(L"BUTTON", L"Back",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
+ x, 0, kButtonWidth, kURLBarHeight,
+ window_, (HMENU) IDC_NAV_BACK, instance_handle_, 0);
+ x += kButtonWidth;
+
+ hwnd = CreateWindow(L"BUTTON", L"Forward",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
+ x, 0, kButtonWidth, kURLBarHeight,
+ window_, (HMENU) IDC_NAV_FORWARD, instance_handle_, 0);
+ x += kButtonWidth;
+
+ hwnd = CreateWindow(L"BUTTON", L"Reload",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
+ x, 0, kButtonWidth, kURLBarHeight,
+ window_, (HMENU) IDC_NAV_RELOAD, instance_handle_, 0);
+ x += kButtonWidth;
+
+ hwnd = CreateWindow(L"BUTTON", L"Stop",
+ WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON ,
+ x, 0, kButtonWidth, kURLBarHeight,
+ window_, (HMENU) IDC_NAV_STOP, instance_handle_, 0);
+ x += kButtonWidth;
+
+ // This control is positioned by PlatformResizeSubViews.
+ url_edit_view_ = CreateWindow(L"EDIT", 0,
+ WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT |
+ ES_AUTOVSCROLL | ES_AUTOHSCROLL,
+ x, 0, 0, 0, window_, 0, instance_handle_, 0);
+
+ default_edit_wnd_proc_ = ui::SetWindowProc(url_edit_view_,
+ Shell::EditWndProc);
+ ui::SetWindowUserData(url_edit_view_, this);
+
+ ShowWindow(window_, SW_SHOW);
+
+ SizeTo(width, height);
+}
+
+void Shell::PlatformSetContents() {
+ SetParent(web_contents_->GetView()->GetNativeView(), window_);
+}
+
+void Shell::SizeTo(int width, int height) {
+ RECT rc, rw;
+ GetClientRect(window_, &rc);
+ GetWindowRect(window_, &rw);
+
+ int client_width = rc.right - rc.left;
+ int window_width = rw.right - rw.left;
+ window_width = (window_width - client_width) + width;
+
+ int client_height = rc.bottom - rc.top;
+ int window_height = rw.bottom - rw.top;
+ window_height = (window_height - client_height) + height;
+
+ // Add space for the url bar.
+ window_height += kURLBarHeight;
+
+ SetWindowPos(window_, NULL, 0, 0, window_width, window_height,
+ SWP_NOMOVE | SWP_NOZORDER);
+}
+
+void Shell::PlatformResizeSubViews() {
+ RECT rc;
+ GetClientRect(window_, &rc);
+
+ int x = kButtonWidth * 4;
+ MoveWindow(url_edit_view_, x, 0, rc.right - x, kURLBarHeight, TRUE);
+
+ MoveWindow(GetContentView(), 0, kURLBarHeight, rc.right,
+ rc.bottom - kURLBarHeight, TRUE);
+}
+
+void Shell::Close() {
+ DestroyWindow(window_);
+}
+
+ATOM Shell::RegisterWindowClass() {
+ WNDCLASSEX window_class;
+ base::win::InitializeWindowClass(
+ kWindowClass,
+ &Shell::WndProc,
+ CS_HREDRAW | CS_VREDRAW,
+ 0,
+ 0,
+ LoadCursor(NULL, IDC_ARROW),
+ NULL,
+ MAKEINTRESOURCE(IDC_CONTENTSHELL),
+ NULL,
+ NULL,
+ &window_class);
+ instance_handle_ = window_class.hInstance;
+ return RegisterClassEx(&window_class);
+}
+
+LRESULT CALLBACK Shell::WndProc(HWND hwnd, UINT message, WPARAM wParam,
+ LPARAM lParam) {
+ Shell* shell = static_cast<Shell*>(ui::GetWindowUserData(hwnd));
+
+ switch (message) {
+ case WM_COMMAND: {
+ int id = LOWORD(wParam);
+ switch (id) {
+ case IDM_NEW_WINDOW:
+ CreateNewWindow(
+ shell->web_contents()->GetBrowserContext(),
+ GURL(), NULL, MSG_ROUTING_NONE, gfx::Size());
+ break;
+ case IDM_CLOSE_WINDOW:
+ DestroyWindow(hwnd);
+ break;
+ case IDM_EXIT:
+ PlatformExit();
+ break;
+ case IDM_SHOW_DEVELOPER_TOOLS:
+ shell->ShowDevTools();
+ break;
+ case IDC_NAV_BACK:
+ shell->GoBackOrForward(-1);
+ break;
+ case IDC_NAV_FORWARD:
+ shell->GoBackOrForward(1);
+ break;
+ case IDC_NAV_RELOAD:
+ shell->Reload();
+ break;
+ case IDC_NAV_STOP:
+ shell->Stop();
+ break;
+ }
+ break;
+ }
+ case WM_DESTROY: {
+ delete shell;
+ return 0;
+ }
+
+ case WM_SIZE: {
+ if (shell->GetContentView())
+ shell->PlatformResizeSubViews();
+ return 0;
+ }
+
+ case WM_WINDOWPOSCHANGED: {
+ // Notify the content view that the window position of its parent window
+ // has been changed by sending window message
+ gfx::NativeView native_view = shell->GetContentView();
+ if (native_view) {
+ SendMessage(native_view, message, wParam, lParam);
+ }
+ break;
+ }
+ }
+
+ return DefWindowProc(hwnd, message, wParam, lParam);
+}
+
+LRESULT CALLBACK Shell::EditWndProc(HWND hwnd, UINT message,
+ WPARAM wParam, LPARAM lParam) {
+ Shell* shell = static_cast<Shell*>(ui::GetWindowUserData(hwnd));
+
+ switch (message) {
+ case WM_CHAR:
+ if (wParam == VK_RETURN) {
+ wchar_t str[kMaxURLLength + 1]; // Leave room for adding a NULL;
+ *(str) = kMaxURLLength;
+ LRESULT str_len = SendMessage(hwnd, EM_GETLINE, 0, (LPARAM)str);
+ if (str_len > 0) {
+ str[str_len] = 0; // EM_GETLINE doesn't NULL terminate.
+ GURL url(str);
+ if (!url.has_scheme())
+ url = GURL(std::wstring(L"http://") + std::wstring(str));
+ shell->LoadURL(url);
+ }
+
+ return 0;
+ }
+ }
+
+ return CallWindowProc(shell->default_edit_wnd_proc_, hwnd, message, wParam,
+ lParam);
+}
+
+void Shell::PlatformSetTitle(const string16& text) {
+ ::SetWindowText(window_, text.c_str());
+}
+
+} // namespace content
diff --git a/content/shell/browser/webkit_test_controller.cc b/content/shell/browser/webkit_test_controller.cc
new file mode 100644
index 0000000..40ed9c5
--- /dev/null
+++ b/content/shell/browser/webkit_test_controller.cc
@@ -0,0 +1,632 @@
+// 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/webkit_test_controller.h"
+
+#include <iostream>
+
+#include "base/base64.h"
+#include "base/command_line.h"
+#include "base/message_loop/message_loop.h"
+#include "base/run_loop.h"
+#include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
+#include "content/public/browser/devtools_manager.h"
+#include "content/public/browser/gpu_data_manager.h"
+#include "content/public/browser/navigation_controller.h"
+#include "content/public/browser/navigation_entry.h"
+#include "content/public/browser/notification_service.h"
+#include "content/public/browser/notification_types.h"
+#include "content/public/browser/render_process_host.h"
+#include "content/public/browser/render_view_host.h"
+#include "content/public/browser/render_widget_host_view.h"
+#include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_view.h"
+#include "content/public/common/content_switches.h"
+#include "content/shell/browser/shell.h"
+#include "content/shell/browser/shell_browser_context.h"
+#include "content/shell/browser/shell_content_browser_client.h"
+#include "content/shell/common/shell_messages.h"
+#include "content/shell/common/shell_switches.h"
+#include "content/shell/common/webkit_test_helpers.h"
+#include "ui/gfx/codec/png_codec.h"
+
+namespace content {
+
+const int kTestSVGWindowWidthDip = 480;
+const int kTestSVGWindowHeightDip = 360;
+
+// WebKitTestResultPrinter ----------------------------------------------------
+
+WebKitTestResultPrinter::WebKitTestResultPrinter(
+ std::ostream* output, std::ostream* error)
+ : state_(DURING_TEST),
+ capture_text_only_(false),
+ encode_binary_data_(false),
+ output_(output),
+ error_(error) {
+}
+
+WebKitTestResultPrinter::~WebKitTestResultPrinter() {
+}
+
+void WebKitTestResultPrinter::PrintTextHeader() {
+ if (state_ != DURING_TEST)
+ return;
+ if (!capture_text_only_)
+ *output_ << "Content-Type: text/plain\n";
+ state_ = IN_TEXT_BLOCK;
+}
+
+void WebKitTestResultPrinter::PrintTextBlock(const std::string& block) {
+ if (state_ != IN_TEXT_BLOCK)
+ return;
+ *output_ << block;
+}
+
+void WebKitTestResultPrinter::PrintTextFooter() {
+ if (state_ != IN_TEXT_BLOCK)
+ return;
+ if (!capture_text_only_) {
+ *output_ << "#EOF\n";
+ output_->flush();
+ }
+ state_ = IN_IMAGE_BLOCK;
+}
+
+void WebKitTestResultPrinter::PrintImageHeader(
+ const std::string& actual_hash,
+ const std::string& expected_hash) {
+ if (state_ != IN_IMAGE_BLOCK || capture_text_only_)
+ return;
+ *output_ << "\nActualHash: " << actual_hash << "\n";
+ if (!expected_hash.empty())
+ *output_ << "\nExpectedHash: " << expected_hash << "\n";
+}
+
+void WebKitTestResultPrinter::PrintImageBlock(
+ const std::vector<unsigned char>& png_image) {
+ if (state_ != IN_IMAGE_BLOCK || capture_text_only_)
+ return;
+ *output_ << "Content-Type: image/png\n";
+ if (encode_binary_data_) {
+ PrintEncodedBinaryData(png_image);
+ return;
+ }
+
+ *output_ << "Content-Length: " << png_image.size() << "\n";
+ output_->write(
+ reinterpret_cast<const char*>(&png_image[0]), png_image.size());
+}
+
+void WebKitTestResultPrinter::PrintImageFooter() {
+ if (state_ != IN_IMAGE_BLOCK)
+ return;
+ if (!capture_text_only_) {
+ *output_ << "#EOF\n";
+ *error_ << "#EOF\n";
+ output_->flush();
+ error_->flush();
+ }
+ state_ = AFTER_TEST;
+}
+
+void WebKitTestResultPrinter::PrintAudioHeader() {
+ DCHECK_EQ(state_, DURING_TEST);
+ if (!capture_text_only_)
+ *output_ << "Content-Type: audio/wav\n";
+ state_ = IN_AUDIO_BLOCK;
+}
+
+void WebKitTestResultPrinter::PrintAudioBlock(
+ const std::vector<unsigned char>& audio_data) {
+ if (state_ != IN_AUDIO_BLOCK || capture_text_only_)
+ return;
+ if (encode_binary_data_) {
+ PrintEncodedBinaryData(audio_data);
+ return;
+ }
+
+ *output_ << "Content-Length: " << audio_data.size() << "\n";
+ output_->write(
+ reinterpret_cast<const char*>(&audio_data[0]), audio_data.size());
+}
+
+void WebKitTestResultPrinter::PrintAudioFooter() {
+ if (state_ != IN_AUDIO_BLOCK)
+ return;
+ if (!capture_text_only_) {
+ *output_ << "#EOF\n";
+ *error_ << "#EOF\n";
+ output_->flush();
+ error_->flush();
+ }
+ state_ = IN_IMAGE_BLOCK;
+}
+
+void WebKitTestResultPrinter::AddMessage(const std::string& message) {
+ AddMessageRaw(message + "\n");
+}
+
+void WebKitTestResultPrinter::AddMessageRaw(const std::string& message) {
+ if (state_ != DURING_TEST)
+ return;
+ *output_ << message;
+}
+
+void WebKitTestResultPrinter::AddErrorMessage(const std::string& message) {
+ if (!capture_text_only_)
+ *error_ << message << "\n";
+ if (state_ != DURING_TEST)
+ return;
+ PrintTextHeader();
+ *output_ << message << "\n";
+ PrintTextFooter();
+ PrintImageFooter();
+}
+
+void WebKitTestResultPrinter::PrintEncodedBinaryData(
+ const std::vector<unsigned char>& data) {
+ *output_ << "Content-Transfer-Encoding: base64\n";
+
+ std::string data_base64;
+ const bool success = base::Base64Encode(
+ base::StringPiece(reinterpret_cast<const char*>(&data[0]), data.size()),
+ &data_base64);
+ DCHECK(success);
+
+ *output_ << "Content-Length: " << data_base64.length() << "\n";
+ output_->write(data_base64.c_str(), data_base64.length());
+}
+
+
+// WebKitTestController -------------------------------------------------------
+
+WebKitTestController* WebKitTestController::instance_ = NULL;
+
+// static
+WebKitTestController* WebKitTestController::Get() {
+ DCHECK(instance_);
+ return instance_;
+}
+
+WebKitTestController::WebKitTestController()
+ : main_window_(NULL),
+ test_phase_(BETWEEN_TESTS) {
+ CHECK(!instance_);
+ instance_ = this;
+ printer_.reset(new WebKitTestResultPrinter(&std::cout, &std::cerr));
+ if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEncodeBinary))
+ printer_->set_encode_binary_data(true);
+ registrar_.Add(this,
+ NOTIFICATION_RENDERER_PROCESS_CREATED,
+ NotificationService::AllSources());
+ GpuDataManager::GetInstance()->AddObserver(this);
+ ResetAfterLayoutTest();
+}
+
+WebKitTestController::~WebKitTestController() {
+ DCHECK(CalledOnValidThread());
+ CHECK(instance_ == this);
+ CHECK(test_phase_ == BETWEEN_TESTS);
+ GpuDataManager::GetInstance()->RemoveObserver(this);
+ DiscardMainWindow();
+ instance_ = NULL;
+}
+
+bool WebKitTestController::PrepareForLayoutTest(
+ const GURL& test_url,
+ const base::FilePath& current_working_directory,
+ bool enable_pixel_dumping,
+ const std::string& expected_pixel_hash) {
+ DCHECK(CalledOnValidThread());
+ test_phase_ = DURING_TEST;
+ current_working_directory_ = current_working_directory;
+ enable_pixel_dumping_ = enable_pixel_dumping;
+ expected_pixel_hash_ = expected_pixel_hash;
+ test_url_ = test_url;
+ printer_->reset();
+ ShellBrowserContext* browser_context =
+ ShellContentBrowserClient::Get()->browser_context();
+ if (test_url.spec().find("compositing/") != std::string::npos)
+ is_compositing_test_ = true;
+ initial_size_ = gfx::Size(
+ Shell::kDefaultTestWindowWidthDip, Shell::kDefaultTestWindowHeightDip);
+ // The W3C SVG layout tests use a different size than the other layout tests.
+ if (test_url.spec().find("W3C-SVG-1.1") != std::string::npos)
+ initial_size_ = gfx::Size(kTestSVGWindowWidthDip, kTestSVGWindowHeightDip);
+ if (!main_window_) {
+ main_window_ = content::Shell::CreateNewWindow(
+ browser_context,
+ GURL(),
+ NULL,
+ MSG_ROUTING_NONE,
+ initial_size_);
+ WebContentsObserver::Observe(main_window_->web_contents());
+ send_configuration_to_next_host_ = true;
+ current_pid_ = base::kNullProcessId;
+ main_window_->LoadURL(test_url);
+ } else {
+#if (defined(OS_WIN) && !defined(USE_AURA)) || \
+ defined(TOOLKIT_GTK) || defined(OS_MACOSX)
+ // Shell::SizeTo is not implemented on all platforms.
+ main_window_->SizeTo(initial_size_.width(), initial_size_.height());
+#endif
+ main_window_->web_contents()->GetRenderViewHost()->GetView()
+ ->SetSize(initial_size_);
+ main_window_->web_contents()->GetRenderViewHost()->WasResized();
+ RenderViewHost* render_view_host =
+ main_window_->web_contents()->GetRenderViewHost();
+ WebPreferences prefs = render_view_host->GetWebkitPreferences();
+ OverrideWebkitPrefs(&prefs);
+ render_view_host->UpdateWebkitPreferences(prefs);
+ SendTestConfiguration();
+
+ NavigationController::LoadURLParams params(test_url);
+ params.transition_type = PageTransitionFromInt(
+ PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR);
+ params.should_clear_history_list = true;
+ main_window_->web_contents()->GetController().LoadURLWithParams(params);
+ main_window_->web_contents()->GetView()->Focus();
+ }
+ main_window_->web_contents()->GetRenderViewHost()->SetActive(true);
+ main_window_->web_contents()->GetRenderViewHost()->Focus();
+ return true;
+}
+
+bool WebKitTestController::ResetAfterLayoutTest() {
+ DCHECK(CalledOnValidThread());
+ printer_->PrintTextFooter();
+ printer_->PrintImageFooter();
+ send_configuration_to_next_host_ = false;
+ test_phase_ = BETWEEN_TESTS;
+ is_compositing_test_ = false;
+ enable_pixel_dumping_ = false;
+ expected_pixel_hash_.clear();
+ test_url_ = GURL();
+ prefs_ = WebPreferences();
+ should_override_prefs_ = false;
+ return true;
+}
+
+void WebKitTestController::SetTempPath(const base::FilePath& temp_path) {
+ temp_path_ = temp_path;
+}
+
+void WebKitTestController::RendererUnresponsive() {
+ DCHECK(CalledOnValidThread());
+ LOG(WARNING) << "renderer unresponsive";
+}
+
+void WebKitTestController::WorkerCrashed() {
+ DCHECK(CalledOnValidThread());
+ printer_->AddErrorMessage("#CRASHED - worker");
+ DiscardMainWindow();
+}
+
+void WebKitTestController::OverrideWebkitPrefs(WebPreferences* prefs) {
+ if (should_override_prefs_) {
+ *prefs = prefs_;
+ } else {
+ ApplyLayoutTestDefaultPreferences(prefs);
+ if (is_compositing_test_) {
+ CommandLine& command_line = *CommandLine::ForCurrentProcess();
+ if (!command_line.HasSwitch(switches::kEnableSoftwareCompositing))
+ prefs->accelerated_2d_canvas_enabled = true;
+ prefs->accelerated_compositing_for_video_enabled = true;
+ prefs->mock_scrollbars_enabled = true;
+ }
+ }
+}
+
+void WebKitTestController::OpenURL(const GURL& url) {
+ if (test_phase_ != DURING_TEST)
+ return;
+
+ Shell::CreateNewWindow(main_window_->web_contents()->GetBrowserContext(),
+ url,
+ main_window_->web_contents()->GetSiteInstance(),
+ MSG_ROUTING_NONE,
+ gfx::Size());
+}
+
+void WebKitTestController::TestFinishedInSecondaryWindow() {
+ RenderViewHost* render_view_host =
+ main_window_->web_contents()->GetRenderViewHost();
+ render_view_host->Send(
+ new ShellViewMsg_NotifyDone(render_view_host->GetRoutingID()));
+}
+
+bool WebKitTestController::IsMainWindow(WebContents* web_contents) const {
+ return main_window_ && web_contents == main_window_->web_contents();
+}
+
+bool WebKitTestController::OnMessageReceived(const IPC::Message& message) {
+ DCHECK(CalledOnValidThread());
+ bool handled = true;
+ IPC_BEGIN_MESSAGE_MAP(WebKitTestController, message)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_PrintMessage, OnPrintMessage)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_TextDump, OnTextDump)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_ImageDump, OnImageDump)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_AudioDump, OnAudioDump)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_OverridePreferences,
+ OnOverridePreferences)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_TestFinished, OnTestFinished)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_ShowDevTools, OnShowDevTools)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseDevTools, OnCloseDevTools)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_GoToOffset, OnGoToOffset)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_Reload, OnReload)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_LoadURLForFrame, OnLoadURLForFrame)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_CaptureSessionHistory,
+ OnCaptureSessionHistory)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_CloseRemainingWindows,
+ OnCloseRemainingWindows)
+ IPC_MESSAGE_HANDLER(ShellViewHostMsg_ResetDone, OnResetDone)
+ IPC_MESSAGE_UNHANDLED(handled = false)
+ IPC_END_MESSAGE_MAP()
+
+ return handled;
+}
+
+void WebKitTestController::PluginCrashed(const base::FilePath& plugin_path,
+ base::ProcessId plugin_pid) {
+ DCHECK(CalledOnValidThread());
+ printer_->AddErrorMessage(
+ base::StringPrintf("#CRASHED - plugin (pid %d)", plugin_pid));
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&WebKitTestController::DiscardMainWindow),
+ base::Unretained(this)));
+}
+
+void WebKitTestController::RenderViewCreated(RenderViewHost* render_view_host) {
+ DCHECK(CalledOnValidThread());
+ // Might be kNullProcessHandle, in which case we will receive a notification
+ // later when the RenderProcessHost was created.
+ if (render_view_host->GetProcess()->GetHandle() != base::kNullProcessHandle)
+ current_pid_ = base::GetProcId(render_view_host->GetProcess()->GetHandle());
+ if (!send_configuration_to_next_host_)
+ return;
+ send_configuration_to_next_host_ = false;
+ SendTestConfiguration();
+}
+
+void WebKitTestController::RenderProcessGone(base::TerminationStatus status) {
+ DCHECK(CalledOnValidThread());
+ if (current_pid_ != base::kNullProcessId) {
+ printer_->AddErrorMessage(std::string("#CRASHED - renderer (pid ") +
+ base::IntToString(current_pid_) + ")");
+ } else {
+ printer_->AddErrorMessage("#CRASHED - renderer");
+ }
+ DiscardMainWindow();
+}
+
+void WebKitTestController::WebContentsDestroyed(WebContents* web_contents) {
+ DCHECK(CalledOnValidThread());
+ printer_->AddErrorMessage("FAIL: main window was destroyed");
+ DiscardMainWindow();
+}
+
+void WebKitTestController::Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ DCHECK(CalledOnValidThread());
+ switch (type) {
+ case NOTIFICATION_RENDERER_PROCESS_CREATED: {
+ if (!main_window_)
+ return;
+ RenderViewHost* render_view_host =
+ main_window_->web_contents()->GetRenderViewHost();
+ if (!render_view_host)
+ return;
+ RenderProcessHost* render_process_host =
+ Source<RenderProcessHost>(source).ptr();
+ if (render_process_host != render_view_host->GetProcess())
+ return;
+ current_pid_ = base::GetProcId(render_process_host->GetHandle());
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+}
+
+void WebKitTestController::OnGpuProcessCrashed(
+ base::TerminationStatus exit_code) {
+ DCHECK(CalledOnValidThread());
+ printer_->AddErrorMessage("#CRASHED - gpu");
+ DiscardMainWindow();
+}
+
+void WebKitTestController::TimeoutHandler() {
+ DCHECK(CalledOnValidThread());
+ printer_->AddErrorMessage(
+ "FAIL: Timed out waiting for notifyDone to be called");
+ DiscardMainWindow();
+}
+
+void WebKitTestController::DiscardMainWindow() {
+ // If we're running a test, we need to close all windows and exit the message
+ // loop. Otherwise, we're already outside of the message loop, and we just
+ // discard the main window.
+ WebContentsObserver::Observe(NULL);
+ if (test_phase_ != BETWEEN_TESTS) {
+ Shell::CloseAllWindows();
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::MessageLoop::QuitClosure());
+ test_phase_ = CLEAN_UP;
+ } else if (main_window_) {
+ main_window_->Close();
+ }
+ main_window_ = NULL;
+ current_pid_ = base::kNullProcessId;
+}
+
+void WebKitTestController::SendTestConfiguration() {
+ RenderViewHost* render_view_host =
+ main_window_->web_contents()->GetRenderViewHost();
+ ShellTestConfiguration params;
+ params.current_working_directory = current_working_directory_;
+ params.temp_path = temp_path_;
+ params.test_url = test_url_;
+ params.enable_pixel_dumping = enable_pixel_dumping_;
+ params.allow_external_pages = CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAllowExternalPages);
+ params.expected_pixel_hash = expected_pixel_hash_;
+ params.initial_size = initial_size_;
+ render_view_host->Send(new ShellViewMsg_SetTestConfiguration(
+ render_view_host->GetRoutingID(), params));
+}
+
+void WebKitTestController::OnTestFinished() {
+ test_phase_ = CLEAN_UP;
+ if (!printer_->output_finished())
+ printer_->PrintImageFooter();
+ RenderViewHost* render_view_host =
+ main_window_->web_contents()->GetRenderViewHost();
+ base::MessageLoop::current()->PostTask(
+ FROM_HERE,
+ base::Bind(base::IgnoreResult(&WebKitTestController::Send),
+ base::Unretained(this),
+ new ShellViewMsg_Reset(render_view_host->GetRoutingID())));
+}
+
+void WebKitTestController::OnImageDump(
+ const std::string& actual_pixel_hash,
+ const SkBitmap& image) {
+ SkAutoLockPixels image_lock(image);
+
+ printer_->PrintImageHeader(actual_pixel_hash, expected_pixel_hash_);
+
+ // Only encode and dump the png if the hashes don't match. Encoding the
+ // image is really expensive.
+ if (actual_pixel_hash != expected_pixel_hash_) {
+ std::vector<unsigned char> png;
+
+ // Only the expected PNGs for Mac have a valid alpha channel.
+#if defined(OS_MACOSX)
+ bool discard_transparency = false;
+#else
+ bool discard_transparency = true;
+#endif
+
+ std::vector<gfx::PNGCodec::Comment> comments;
+ comments.push_back(gfx::PNGCodec::Comment("checksum", actual_pixel_hash));
+ bool success = gfx::PNGCodec::Encode(
+ static_cast<const unsigned char*>(image.getPixels()),
+ gfx::PNGCodec::FORMAT_BGRA,
+ gfx::Size(image.width(), image.height()),
+ static_cast<int>(image.rowBytes()),
+ discard_transparency,
+ comments,
+ &png);
+ if (success)
+ printer_->PrintImageBlock(png);
+ }
+ printer_->PrintImageFooter();
+}
+
+void WebKitTestController::OnAudioDump(const std::vector<unsigned char>& dump) {
+ printer_->PrintAudioHeader();
+ printer_->PrintAudioBlock(dump);
+ printer_->PrintAudioFooter();
+}
+
+void WebKitTestController::OnTextDump(const std::string& dump) {
+ printer_->PrintTextHeader();
+ printer_->PrintTextBlock(dump);
+ printer_->PrintTextFooter();
+}
+
+void WebKitTestController::OnPrintMessage(const std::string& message) {
+ printer_->AddMessageRaw(message);
+}
+
+void WebKitTestController::OnOverridePreferences(const WebPreferences& prefs) {
+ should_override_prefs_ = true;
+ prefs_ = prefs;
+}
+
+void WebKitTestController::OnShowDevTools() {
+ main_window_->ShowDevTools();
+}
+
+void WebKitTestController::OnCloseDevTools() {
+ main_window_->CloseDevTools();
+}
+
+void WebKitTestController::OnGoToOffset(int offset) {
+ main_window_->GoBackOrForward(offset);
+}
+
+void WebKitTestController::OnReload() {
+ main_window_->Reload();
+}
+
+void WebKitTestController::OnLoadURLForFrame(const GURL& url,
+ const std::string& frame_name) {
+ main_window_->LoadURLForFrame(url, frame_name);
+}
+
+void WebKitTestController::OnCaptureSessionHistory() {
+ std::vector<int> routing_ids;
+ std::vector<std::vector<PageState> > session_histories;
+ std::vector<unsigned> current_entry_indexes;
+
+ RenderViewHost* render_view_host =
+ main_window_->web_contents()->GetRenderViewHost();
+
+ for (std::vector<Shell*>::iterator window = Shell::windows().begin();
+ window != Shell::windows().end();
+ ++window) {
+ WebContents* web_contents = (*window)->web_contents();
+ // Only capture the history from windows in the same process as the main
+ // window. During layout tests, we only use two processes when an
+ // devtools window is open. This should not happen during history navigation
+ // tests.
+ if (render_view_host->GetProcess() !=
+ web_contents->GetRenderViewHost()->GetProcess()) {
+ NOTREACHED();
+ continue;
+ }
+ routing_ids.push_back(web_contents->GetRenderViewHost()->GetRoutingID());
+ current_entry_indexes.push_back(
+ web_contents->GetController().GetCurrentEntryIndex());
+ std::vector<PageState> history;
+ for (int entry = 0; entry < web_contents->GetController().GetEntryCount();
+ ++entry) {
+ PageState state = web_contents->GetController().GetEntryAtIndex(entry)->
+ GetPageState();
+ if (!state.IsValid()) {
+ state = PageState::CreateFromURL(
+ web_contents->GetController().GetEntryAtIndex(entry)->GetURL());
+ }
+ history.push_back(state);
+ }
+ session_histories.push_back(history);
+ }
+
+ Send(new ShellViewMsg_SessionHistory(render_view_host->GetRoutingID(),
+ routing_ids,
+ session_histories,
+ current_entry_indexes));
+}
+
+void WebKitTestController::OnCloseRemainingWindows() {
+ DevToolsManager::GetInstance()->CloseAllClientHosts();
+ std::vector<Shell*> open_windows(Shell::windows());
+ for (size_t i = 0; i < open_windows.size(); ++i) {
+ if (open_windows[i] != main_window_)
+ open_windows[i]->Close();
+ }
+ base::MessageLoop::current()->RunUntilIdle();
+}
+
+void WebKitTestController::OnResetDone() {
+ base::MessageLoop::current()->PostTask(FROM_HERE,
+ base::MessageLoop::QuitClosure());
+}
+
+} // namespace content
diff --git a/content/shell/browser/webkit_test_controller.h b/content/shell/browser/webkit_test_controller.h
new file mode 100644
index 0000000..58d1fa9
--- /dev/null
+++ b/content/shell/browser/webkit_test_controller.h
@@ -0,0 +1,219 @@
+// 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.
+
+#ifndef CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_
+#define CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_
+
+#include <ostream>
+#include <string>
+
+#include "base/cancelable_callback.h"
+#include "base/files/file_path.h"
+#include "base/synchronization/lock.h"
+#include "base/threading/non_thread_safe.h"
+#include "content/public/browser/gpu_data_manager_observer.h"
+#include "content/public/browser/notification_observer.h"
+#include "content/public/browser/notification_registrar.h"
+#include "content/public/browser/render_view_host_observer.h"
+#include "content/public/browser/web_contents_observer.h"
+#include "ui/gfx/size.h"
+#include "webkit/common/webpreferences.h"
+
+#if defined(OS_ANDROID)
+#include "base/threading/thread_restrictions.h"
+#endif
+
+class SkBitmap;
+
+namespace content {
+
+class Shell;
+
+#if defined(OS_ANDROID)
+// Android uses a nested message loop for running layout tests because the
+// default message loop, provided by the system, does not offer a blocking
+// Run() method. The loop itself, implemented as NestedMessagePumpAndroid,
+// uses a base::WaitableEvent allowing it to sleep until more events arrive.
+class ScopedAllowWaitForAndroidLayoutTests {
+ private:
+ base::ThreadRestrictions::ScopedAllowWait wait;
+};
+#endif
+
+class WebKitTestResultPrinter {
+ public:
+ WebKitTestResultPrinter(std::ostream* output, std::ostream* error);
+ ~WebKitTestResultPrinter();
+
+ void reset() {
+ state_ = DURING_TEST;
+ }
+ bool output_finished() const { return state_ == AFTER_TEST; }
+ void set_capture_text_only(bool capture_text_only) {
+ capture_text_only_ = capture_text_only;
+ }
+
+ void set_encode_binary_data(bool encode_binary_data) {
+ encode_binary_data_ = encode_binary_data;
+ }
+
+ void PrintTextHeader();
+ void PrintTextBlock(const std::string& block);
+ void PrintTextFooter();
+
+ void PrintImageHeader(const std::string& actual_hash,
+ const std::string& expected_hash);
+ void PrintImageBlock(const std::vector<unsigned char>& png_image);
+ void PrintImageFooter();
+
+ void PrintAudioHeader();
+ void PrintAudioBlock(const std::vector<unsigned char>& audio_data);
+ void PrintAudioFooter();
+
+ void AddMessage(const std::string& message);
+ void AddMessageRaw(const std::string& message);
+ void AddErrorMessage(const std::string& message);
+
+ private:
+ void PrintEncodedBinaryData(const std::vector<unsigned char>& data);
+
+ enum State {
+ DURING_TEST,
+ IN_TEXT_BLOCK,
+ IN_AUDIO_BLOCK,
+ IN_IMAGE_BLOCK,
+ AFTER_TEST
+ };
+ State state_;
+
+ bool capture_text_only_;
+ bool encode_binary_data_;
+
+ std::ostream* output_;
+ std::ostream* error_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebKitTestResultPrinter);
+};
+
+class WebKitTestController : public base::NonThreadSafe,
+ public WebContentsObserver,
+ public NotificationObserver,
+ public GpuDataManagerObserver {
+ public:
+ static WebKitTestController* Get();
+
+ WebKitTestController();
+ virtual ~WebKitTestController();
+
+ // True if the controller is ready for testing.
+ bool PrepareForLayoutTest(const GURL& test_url,
+ const base::FilePath& current_working_directory,
+ bool enable_pixel_dumping,
+ const std::string& expected_pixel_hash);
+ // True if the controller was reset successfully.
+ bool ResetAfterLayoutTest();
+
+ void SetTempPath(const base::FilePath& temp_path);
+ void RendererUnresponsive();
+ void WorkerCrashed();
+ void OverrideWebkitPrefs(WebPreferences* prefs);
+ void OpenURL(const GURL& url);
+ void TestFinishedInSecondaryWindow();
+ bool IsMainWindow(WebContents* web_contents) const;
+
+ WebKitTestResultPrinter* printer() { return printer_.get(); }
+ void set_printer(WebKitTestResultPrinter* printer) {
+ printer_.reset(printer);
+ }
+
+ // WebContentsObserver implementation.
+ virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;
+ virtual void PluginCrashed(const base::FilePath& plugin_path,
+ base::ProcessId plugin_pid) OVERRIDE;
+ virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE;
+ virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE;
+ virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE;
+
+ // NotificationObserver implementation.
+ virtual void Observe(int type,
+ const NotificationSource& source,
+ const NotificationDetails& details) OVERRIDE;
+
+ // GpuDataManagerObserver implementation.
+ virtual void OnGpuProcessCrashed(base::TerminationStatus exit_code) OVERRIDE;
+
+ private:
+ enum TestPhase {
+ BETWEEN_TESTS,
+ DURING_TEST,
+ CLEAN_UP
+ };
+
+ static WebKitTestController* instance_;
+
+ void TimeoutHandler();
+ void DiscardMainWindow();
+ void SendTestConfiguration();
+
+ // Message handlers.
+ void OnAudioDump(const std::vector<unsigned char>& audio_dump);
+ void OnImageDump(const std::string& actual_pixel_hash, const SkBitmap& image);
+ void OnTextDump(const std::string& dump);
+ void OnPrintMessage(const std::string& message);
+ void OnOverridePreferences(const WebPreferences& prefs);
+ void OnTestFinished();
+ void OnShowDevTools();
+ void OnCloseDevTools();
+ void OnGoToOffset(int offset);
+ void OnReload();
+ void OnLoadURLForFrame(const GURL& url, const std::string& frame_name);
+ void OnCaptureSessionHistory();
+ void OnCloseRemainingWindows();
+ void OnResetDone();
+
+ scoped_ptr<WebKitTestResultPrinter> printer_;
+
+ base::FilePath current_working_directory_;
+ base::FilePath temp_path_;
+
+ Shell* main_window_;
+
+ // The PID of the render process of the render view host of main_window_.
+ int current_pid_;
+
+ // True if we should set the test configuration to the next RenderViewHost
+ // created.
+ bool send_configuration_to_next_host_;
+
+ // What phase of running an individual test we are currently in.
+ TestPhase test_phase_;
+
+ // True if the currently running test is a compositing test.
+ bool is_compositing_test_;
+
+ // Per test config.
+ bool enable_pixel_dumping_;
+ std::string expected_pixel_hash_;
+ gfx::Size initial_size_;
+ GURL test_url_;
+
+ // True if the WebPreferences of newly created RenderViewHost should be
+ // overridden with prefs_.
+ bool should_override_prefs_;
+ WebPreferences prefs_;
+
+ NotificationRegistrar registrar_;
+
+#if defined(OS_ANDROID)
+ // Because of the nested message pump implementation, Android needs to allow
+ // waiting on the UI thread while layout tests are being ran.
+ ScopedAllowWaitForAndroidLayoutTests reduced_restrictions_;
+#endif
+
+ DISALLOW_COPY_AND_ASSIGN(WebKitTestController);
+};
+
+} // namespace content
+
+#endif // CONTENT_SHELL_BROWSER_WEBKIT_TEST_CONTROLLER_H_