summaryrefslogtreecommitdiffstats
path: root/ios
diff options
context:
space:
mode:
authorstuartmorgan <stuartmorgan@chromium.org>2015-05-26 21:13:34 -0700
committerCommit bot <commit-bot@chromium.org>2015-05-27 04:15:14 +0000
commita5df0663172d93a056cb74a034867c3f1e3b4a9b (patch)
tree1ac5bbb8fb572265dead41dd783015c5e8e8ede4 /ios
parent2eb910dffeee1b1ea0ffaff5eae81ea496155046 (diff)
downloadchromium_src-a5df0663172d93a056cb74a034867c3f1e3b4a9b.zip
chromium_src-a5df0663172d93a056cb74a034867c3f1e3b4a9b.tar.gz
chromium_src-a5df0663172d93a056cb74a034867c3f1e3b4a9b.tar.bz2
Upstream the iOS web_shell and supporting code
This upstreams the iOS app/ and shell/ directories. - app/ is equivalent to the content/ versions, and is heavily based on that code. - shell/ is the web_shell target, which is an incredibly stripped-down browser build on ios/web, in the spirit of content_shell. Currently web_shell is extremely minimal, but allows basic browsing to test ios/web/. BUG=464810 Review URL: https://codereview.chromium.org/1149323004 Cr-Commit-Position: refs/heads/master@{#331526}
Diffstat (limited to 'ios')
-rw-r--r--ios/ios.gyp1
-rw-r--r--ios/web/app/web_main.mm19
-rw-r--r--ios/web/app/web_main_loop.h99
-rw-r--r--ios/web/app/web_main_loop.mm278
-rw-r--r--ios/web/app/web_main_runner.h29
-rw-r--r--ios/web/app/web_main_runner.mm133
-rw-r--r--ios/web/ios_web.gyp29
-rw-r--r--ios/web/ios_web_shell.gyp66
-rw-r--r--ios/web/public/app/web_main.h39
-rw-r--r--ios/web/public/app/web_main_delegate.h30
-rw-r--r--ios/web/public/app/web_main_parts.h78
-rw-r--r--ios/web/public/app/web_main_parts.mm13
-rw-r--r--ios/web/shell/Info.plist121
-rw-r--r--ios/web/shell/MainView.xib43
-rw-r--r--ios/web/shell/app_delegate.h16
-rw-r--r--ios/web/shell/app_delegate.mm64
-rw-r--r--ios/web/shell/shell_browser_state.h41
-rw-r--r--ios/web/shell/shell_browser_state.mm43
-rw-r--r--ios/web/shell/shell_main_delegate.h29
-rw-r--r--ios/web/shell/shell_main_delegate.mm22
-rw-r--r--ios/web/shell/shell_network_delegate.cc95
-rw-r--r--ios/web/shell/shell_network_delegate.h61
-rw-r--r--ios/web/shell/shell_url_request_context_getter.cc159
-rw-r--r--ios/web/shell/shell_url_request_context_getter.h62
-rw-r--r--ios/web/shell/shell_web_client.h36
-rw-r--r--ios/web/shell/shell_web_client.mm36
-rw-r--r--ios/web/shell/shell_web_main_parts.h32
-rw-r--r--ios/web/shell/shell_web_main_parts.mm21
-rw-r--r--ios/web/shell/view_controller.h29
-rw-r--r--ios/web/shell/view_controller.mm334
-rw-r--r--ios/web/shell/web_exe_main.mm14
31 files changed, 2072 insertions, 0 deletions
diff --git a/ios/ios.gyp b/ios/ios.gyp
index 84b5e95..4caf955 100644
--- a/ios/ios.gyp
+++ b/ios/ios.gyp
@@ -20,6 +20,7 @@
'provider/ios_provider_web.gyp:*',
'testing/ios_testing.gyp:*',
'web/ios_web.gyp:*',
+ 'web/ios_web_shell.gyp:*',
'web/ios_web_unittests.gyp:*',
],
},
diff --git a/ios/web/app/web_main.mm b/ios/web/app/web_main.mm
new file mode 100644
index 0000000..5e5aa2b
--- /dev/null
+++ b/ios/web/app/web_main.mm
@@ -0,0 +1,19 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/app/web_main_runner.h"
+#include "ios/web/public/app/web_main.h"
+
+namespace web {
+
+WebMain::WebMain(const WebMainParams& params) {
+ web_main_runner_.reset(WebMainRunner::Create());
+ web_main_runner_->Initialize(params);
+}
+
+WebMain::~WebMain() {
+ web_main_runner_->ShutDown();
+}
+
+} // namespace web
diff --git a/ios/web/app/web_main_loop.h b/ios/web/app/web_main_loop.h
new file mode 100644
index 0000000..8fd9178
--- /dev/null
+++ b/ios/web/app/web_main_loop.h
@@ -0,0 +1,99 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_APP_WEB_MAIN_LOOP_H_
+#define IOS_WEB_APP_WEB_MAIN_LOOP_H_
+
+#include "base/basictypes.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace base {
+class CommandLine;
+class FilePath;
+class MessageLoop;
+class PowerMonitor;
+class SystemMonitor;
+} // namespace base
+
+namespace net {
+class NetworkChangeNotifier;
+} // namespace net
+
+namespace web {
+class CookieNotificationBridge;
+class WebMainParts;
+class WebThreadImpl;
+
+// Implements the main web loop stages called from WebMainRunner.
+// See comments in web_main_parts.h for additional info.
+class WebMainLoop {
+ public:
+ explicit WebMainLoop();
+ virtual ~WebMainLoop();
+
+ void Init();
+
+ void EarlyInitialization();
+ void MainMessageLoopStart();
+
+ // Creates and starts running the tasks needed to complete startup.
+ void CreateStartupTasks();
+
+ // Performs the shutdown sequence, starting with PostMainMessageLoopRun
+ // through stopping threads to PostDestroyThreads.
+ void ShutdownThreadsAndCleanUp();
+
+ int GetResultCode() const { return result_code_; }
+
+ private:
+ void InitializeMainThread();
+
+ // Called just before creating the threads
+ int PreCreateThreads();
+
+ // Creates all secondary threads.
+ int CreateThreads();
+
+ // Called right after the web threads have been started.
+ int WebThreadsStarted();
+
+ // Called just before attaching to the main message loop.
+ int PreMainMessageLoopRun();
+
+ // Members initialized on construction ---------------------------------------
+ int result_code_;
+ // True if the non-UI threads were created.
+ bool created_threads_;
+
+ // Members initialized in |MainMessageLoopStart()| ---------------------------
+ scoped_ptr<base::MessageLoop> main_message_loop_;
+ scoped_ptr<base::SystemMonitor> system_monitor_;
+ scoped_ptr<base::PowerMonitor> power_monitor_;
+ scoped_ptr<net::NetworkChangeNotifier> network_change_notifier_;
+
+ // Destroy parts_ before main_message_loop_ (required) and before other
+ // classes constructed in web (but after main_thread_).
+ scoped_ptr<WebMainParts> parts_;
+
+ // Members initialized in |InitializeMainThread()| ---------------------------
+ // This must get destroyed before other threads that are created in parts_.
+ scoped_ptr<WebThreadImpl> main_thread_;
+
+ // Members initialized in |RunMainMessageLoopParts()| ------------------------
+ scoped_ptr<WebThreadImpl> db_thread_;
+ scoped_ptr<WebThreadImpl> file_user_blocking_thread_;
+ scoped_ptr<WebThreadImpl> file_thread_;
+ scoped_ptr<WebThreadImpl> cache_thread_;
+ scoped_ptr<WebThreadImpl> io_thread_;
+
+ // Members initialized in |WebThreadsStarted()| --------------------------
+ scoped_ptr<CookieNotificationBridge> cookie_notification_bridge_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebMainLoop);
+};
+
+} // namespace web
+
+#endif // IOS_WEB_APP_WEB_MAIN_LOOP_H_
diff --git a/ios/web/app/web_main_loop.mm b/ios/web/app/web_main_loop.mm
new file mode 100644
index 0000000..b3300d4
--- /dev/null
+++ b/ios/web/app/web_main_loop.mm
@@ -0,0 +1,278 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/app/web_main_loop.h"
+
+#include "base/bind.h"
+#include "base/command_line.h"
+#include "base/logging.h"
+#include "base/message_loop/message_loop.h"
+#include "base/metrics/histogram.h"
+#include "base/path_service.h"
+#include "base/power_monitor/power_monitor.h"
+#include "base/power_monitor/power_monitor_device_source.h"
+#include "base/process/process_metrics.h"
+#include "base/system_monitor/system_monitor.h"
+#include "base/threading/thread_restrictions.h"
+#include "crypto/nss_util.h"
+#include "ios/web/net/cookie_notification_bridge.h"
+#include "ios/web/public/app/web_main_parts.h"
+#include "ios/web/public/web_client.h"
+#include "ios/web/web_thread_impl.h"
+#include "net/base/network_change_notifier.h"
+
+namespace web {
+
+// The currently-running WebMainLoop. There can be one or zero.
+// TODO(rohitrao): Desktop uses this to implement
+// ImmediateShutdownAndExitProcess. If we don't need that functionality, we can
+// remove this.
+WebMainLoop* g_current_web_main_loop = nullptr;
+
+WebMainLoop::WebMainLoop() : result_code_(0), created_threads_(false) {
+ DCHECK(!g_current_web_main_loop);
+ g_current_web_main_loop = this;
+}
+
+WebMainLoop::~WebMainLoop() {
+ DCHECK_EQ(this, g_current_web_main_loop);
+ g_current_web_main_loop = nullptr;
+}
+
+void WebMainLoop::Init() {
+ parts_.reset(web::GetWebClient()->CreateWebMainParts());
+}
+
+void WebMainLoop::EarlyInitialization() {
+ if (parts_) {
+ parts_->PreEarlyInitialization();
+ }
+
+#if !defined(USE_OPENSSL)
+ // We want to be sure to init NSPR on the main thread.
+ crypto::EnsureNSPRInit();
+#endif // !defined(USE_OPENSSL)
+
+ if (parts_) {
+ parts_->PostEarlyInitialization();
+ }
+}
+
+void WebMainLoop::MainMessageLoopStart() {
+ if (parts_) {
+ parts_->PreMainMessageLoopStart();
+ }
+
+ // Create a MessageLoop if one does not already exist for the current thread.
+ if (!base::MessageLoop::current()) {
+ main_message_loop_.reset(new base::MessageLoopForUI);
+ }
+ // Note: In Chrome, Attach() is called in
+ // ChromeBrowserMainPartsIOS::PreMainMessageLoopStart().
+ base::MessageLoopForUI::current()->Attach();
+
+ InitializeMainThread();
+
+#if 0
+ // TODO(droger): SystemMonitor is not working properly on iOS.
+ // See http://crbug.com/228014.
+ system_monitor_.reset(new base::SystemMonitor);
+#endif
+ // TODO(rohitrao): Do we need PowerMonitor on iOS, or can we get rid of it?
+ scoped_ptr<base::PowerMonitorSource> power_monitor_source(
+ new base::PowerMonitorDeviceSource());
+ power_monitor_.reset(new base::PowerMonitor(power_monitor_source.Pass()));
+ network_change_notifier_.reset(net::NetworkChangeNotifier::Create());
+
+ if (parts_) {
+ parts_->PostMainMessageLoopStart();
+ }
+}
+
+void WebMainLoop::CreateStartupTasks() {
+ int result = 0;
+ result = PreCreateThreads();
+ if (result > 0)
+ return;
+
+ result = CreateThreads();
+ if (result > 0)
+ return;
+
+ result = WebThreadsStarted();
+ if (result > 0)
+ return;
+
+ result = PreMainMessageLoopRun();
+ if (result > 0)
+ return;
+}
+
+int WebMainLoop::PreCreateThreads() {
+ if (parts_) {
+ result_code_ = parts_->PreCreateThreads();
+ }
+
+ return result_code_;
+}
+
+int WebMainLoop::CreateThreads() {
+ base::Thread::Options default_options;
+ base::Thread::Options io_message_loop_options;
+ io_message_loop_options.message_loop_type = base::MessageLoop::TYPE_IO;
+ base::Thread::Options ui_message_loop_options;
+ ui_message_loop_options.message_loop_type = base::MessageLoop::TYPE_UI;
+
+ // Start threads in the order they occur in the WebThread::ID
+ // enumeration, except for WebThread::UI which is the main
+ // thread.
+ //
+ // Must be size_t so we can increment it.
+ for (size_t thread_id = WebThread::UI + 1; thread_id < WebThread::ID_COUNT;
+ ++thread_id) {
+ scoped_ptr<WebThreadImpl>* thread_to_start = nullptr;
+ base::Thread::Options* options = &default_options;
+
+ switch (thread_id) {
+ // TODO(rohitrao): We probably do not need all of these threads. Remove
+ // the ones that serve no purpose. http://crbug.com/365909
+ case WebThread::DB:
+ thread_to_start = &db_thread_;
+ break;
+ case WebThread::FILE_USER_BLOCKING:
+ thread_to_start = &file_user_blocking_thread_;
+ break;
+ case WebThread::FILE:
+ thread_to_start = &file_thread_;
+ options = &io_message_loop_options;
+ break;
+ case WebThread::CACHE:
+ thread_to_start = &cache_thread_;
+ options = &io_message_loop_options;
+ break;
+ case WebThread::IO:
+ thread_to_start = &io_thread_;
+ options = &io_message_loop_options;
+ break;
+ case WebThread::UI:
+ case WebThread::ID_COUNT:
+ default:
+ NOTREACHED();
+ break;
+ }
+
+ WebThread::ID id = static_cast<WebThread::ID>(thread_id);
+
+ if (thread_to_start) {
+ (*thread_to_start).reset(new WebThreadImpl(id));
+ (*thread_to_start)->StartWithOptions(*options);
+ } else {
+ NOTREACHED();
+ }
+ }
+ created_threads_ = true;
+ return result_code_;
+}
+
+int WebMainLoop::PreMainMessageLoopRun() {
+ if (parts_) {
+ parts_->PreMainMessageLoopRun();
+ }
+
+ // If the UI thread blocks, the whole UI is unresponsive.
+ // Do not allow disk IO from the UI thread.
+ base::ThreadRestrictions::SetIOAllowed(false);
+ base::ThreadRestrictions::DisallowWaiting();
+ return result_code_;
+}
+
+void WebMainLoop::ShutdownThreadsAndCleanUp() {
+ if (!created_threads_) {
+ // Called early, nothing to do
+ return;
+ }
+
+ // Teardown may start in PostMainMessageLoopRun, and during teardown we
+ // need to be able to perform IO.
+ base::ThreadRestrictions::SetIOAllowed(true);
+ WebThread::PostTask(
+ WebThread::IO, FROM_HERE,
+ base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
+ true));
+
+ if (parts_) {
+ parts_->PostMainMessageLoopRun();
+ }
+
+ // Must be size_t so we can subtract from it.
+ for (size_t thread_id = WebThread::ID_COUNT - 1;
+ thread_id >= (WebThread::UI + 1); --thread_id) {
+ // Find the thread object we want to stop. Looping over all valid
+ // WebThread IDs and DCHECKing on a missing case in the switch
+ // statement helps avoid a mismatch between this code and the
+ // WebThread::ID enumeration.
+ //
+ // The destruction order is the reverse order of occurrence in the
+ // WebThread::ID list. The rationale for the order is as
+ // follows (need to be filled in a bit):
+ //
+ //
+ // - The IO thread is the only user of the CACHE thread.
+ //
+ // - (Not sure why DB stops last.)
+ switch (thread_id) {
+ case WebThread::DB:
+ db_thread_.reset();
+ break;
+ case WebThread::FILE_USER_BLOCKING:
+ file_user_blocking_thread_.reset();
+ break;
+ case WebThread::FILE:
+ file_thread_.reset();
+ break;
+ case WebThread::CACHE:
+ cache_thread_.reset();
+ break;
+ case WebThread::IO:
+ io_thread_.reset();
+ break;
+ case WebThread::UI:
+ case WebThread::ID_COUNT:
+ default:
+ NOTREACHED();
+ break;
+ }
+ }
+
+ // Close the blocking I/O pool after the other threads. Other threads such
+ // as the I/O thread may need to schedule work like closing files or flushing
+ // data during shutdown, so the blocking pool needs to be available. There
+ // may also be slow operations pending that will block shutdown, so closing
+ // it here (which will block until required operations are complete) gives
+ // more head start for those operations to finish.
+ WebThreadImpl::ShutdownThreadPool();
+
+ if (parts_) {
+ parts_->PostDestroyThreads();
+ }
+}
+
+void WebMainLoop::InitializeMainThread() {
+ const char* kThreadName = "CrWebMain";
+ base::PlatformThread::SetName(kThreadName);
+ if (main_message_loop_) {
+ main_message_loop_->set_thread_name(kThreadName);
+ }
+
+ // Register the main thread by instantiating it, but don't call any methods.
+ main_thread_.reset(
+ new WebThreadImpl(WebThread::UI, base::MessageLoop::current()));
+}
+
+int WebMainLoop::WebThreadsStarted() {
+ cookie_notification_bridge_.reset(new CookieNotificationBridge);
+ return result_code_;
+}
+
+} // namespace web
diff --git a/ios/web/app/web_main_runner.h b/ios/web/app/web_main_runner.h
new file mode 100644
index 0000000..c0c3c6f
--- /dev/null
+++ b/ios/web/app/web_main_runner.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_APP_WEB_MAIN_RUNNER_H_
+#define IOS_WEB_APP_WEB_MAIN_RUNNER_H_
+
+#include "ios/web/public/app/web_main.h"
+
+namespace web {
+
+// This class is responsible for web initialization and shutdown.
+class WebMainRunner {
+ public:
+ virtual ~WebMainRunner() {}
+
+ // Create a new WebMainRunner object.
+ static WebMainRunner* Create();
+
+ // Initialize all necessary web state.
+ virtual int Initialize(const WebMainParams& params) = 0;
+
+ // Shut down the web state.
+ virtual void ShutDown() = 0;
+};
+
+} // namespace web
+
+#endif // IOS_WEB_APP_WEB_MAIN_RUNNER_H_
diff --git a/ios/web/app/web_main_runner.mm b/ios/web/app/web_main_runner.mm
new file mode 100644
index 0000000..ff50552
--- /dev/null
+++ b/ios/web/app/web_main_runner.mm
@@ -0,0 +1,133 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/app/web_main_runner.h"
+
+#include "base/at_exit.h"
+#include "base/command_line.h"
+#include "base/i18n/icu_util.h"
+#include "base/logging.h"
+#include "base/metrics/statistics_recorder.h"
+#include "ios/web/app/web_main_loop.h"
+#include "ios/web/public/web_client.h"
+#include "ui/base/ui_base_paths.h"
+
+namespace web {
+
+class WebMainRunnerImpl : public WebMainRunner {
+ public:
+ WebMainRunnerImpl()
+ : is_initialized_(false),
+ is_shutdown_(false),
+ completed_basic_startup_(false),
+ delegate_(nullptr) {}
+
+ ~WebMainRunnerImpl() override {
+ if (is_initialized_ && !is_shutdown_) {
+ ShutDown();
+ }
+ }
+
+ int Initialize(const WebMainParams& params) override {
+ ////////////////////////////////////////////////////////////////////////
+ // ContentMainRunnerImpl::Initialize()
+ //
+ is_initialized_ = true;
+ delegate_ = params.delegate;
+
+ // TODO(rohitrao): Chrome for iOS initializes this in main(), because it's
+ // needed for breakpad. Are we really going to require that all embedders
+ // initialize an AtExitManager in main()?
+ exit_manager_.reset(new base::AtExitManager);
+
+ // There is no way to pass commandline flags to process on iOS, so the
+ // CommandLine is always initialized empty. Embedders can add switches in
+ // |BasicStartupComplete|.
+ base::CommandLine::Init(0, nullptr);
+ if (delegate_) {
+ delegate_->BasicStartupComplete();
+ }
+ completed_basic_startup_ = true;
+
+ // TODO(rohitrao): Should we instead require that all embedders call
+ // SetWebClient()?
+ if (!GetWebClient())
+ SetWebClient(&empty_web_client_);
+
+#if defined(USE_NSS)
+ crypto::EarlySetupForNSSInit();
+#endif
+
+ // TODO(rohitrao): Desktop calls content::RegisterContentSchemes(true) here.
+ // Do we need similar scheme registration on iOS?
+ ui::RegisterPathProvider();
+
+ CHECK(base::i18n::InitializeICU());
+
+ ////////////////////////////////////////////////////////////
+ // BrowserMainRunnerImpl::Initialize()
+ base::StatisticsRecorder::Initialize();
+
+ main_loop_.reset(new WebMainLoop());
+ main_loop_->Init();
+ main_loop_->EarlyInitialization();
+ main_loop_->MainMessageLoopStart();
+ main_loop_->CreateStartupTasks();
+ int result_code = main_loop_->GetResultCode();
+ if (result_code > 0)
+ return result_code;
+
+ // Return -1 to indicate no early termination.
+ return -1;
+ }
+
+ void ShutDown() override {
+ ////////////////////////////////////////////////////////////////////
+ // BrowserMainRunner::Shutdown()
+ //
+ DCHECK(is_initialized_);
+ DCHECK(!is_shutdown_);
+ main_loop_->ShutdownThreadsAndCleanUp();
+ main_loop_.reset(nullptr);
+
+ ////////////////////////////////////////////////////////////////////
+ // ContentMainRunner::Shutdown()
+ //
+ if (completed_basic_startup_ && delegate_) {
+ delegate_->ProcessExiting();
+ }
+
+ exit_manager_.reset(nullptr);
+ delegate_ = nullptr;
+ is_shutdown_ = true;
+ }
+
+ protected:
+ // True if we have started to initialize the runner.
+ bool is_initialized_;
+
+ // True if the runner has been shut down.
+ bool is_shutdown_;
+
+ // True if basic startup was completed.
+ bool completed_basic_startup_;
+
+ // The delegate will outlive this object.
+ WebMainDelegate* delegate_;
+
+ // Used if the embedder doesn't set one.
+ WebClient empty_web_client_;
+
+ scoped_ptr<base::AtExitManager> exit_manager_;
+ scoped_ptr<WebMainLoop> main_loop_;
+
+ DISALLOW_COPY_AND_ASSIGN(WebMainRunnerImpl);
+};
+
+// static
+WebMainRunner* WebMainRunner::Create() {
+ return new WebMainRunnerImpl();
+}
+
+} // namespace web
diff --git a/ios/web/ios_web.gyp b/ios/web/ios_web.gyp
index 030d9ada..d5ab122 100644
--- a/ios/web/ios_web.gyp
+++ b/ios/web/ios_web.gyp
@@ -7,6 +7,35 @@
'chromium_code': 1,
},
'targets': [
+ {
+ 'target_name': 'ios_web_app',
+ 'type': 'static_library',
+ 'include_dirs': [
+ '../..',
+ ],
+ 'dependencies': [
+ 'ios_web',
+ 'ios_web_thread',
+ '../../base/base.gyp:base',
+ '../../base/base.gyp:base_i18n',
+ '../../crypto/crypto.gyp:crypto',
+ '../../net/net.gyp:net',
+ '../../ui/base/ui_base.gyp:ui_base',
+ '../../ui/gfx/gfx.gyp:gfx',
+ '../../ui/gfx/gfx.gyp:gfx_geometry',
+ ],
+ 'sources': [
+ 'app/web_main.mm',
+ 'app/web_main_loop.h',
+ 'app/web_main_loop.mm',
+ 'app/web_main_runner.h',
+ 'app/web_main_runner.mm',
+ 'public/app/web_main.h',
+ 'public/app/web_main_delegate.h',
+ 'public/app/web_main_parts.h',
+ 'public/app/web_main_parts.mm',
+ ],
+ },
# Note: any embedder using ios_web will for now need to include either
# ios_web_thread (any new embedder) or ios_web_content_thread_shim (Chrome).
# This will become unnecessary once Chrome switches to using ios_web_thread,
diff --git a/ios/web/ios_web_shell.gyp b/ios/web/ios_web_shell.gyp
new file mode 100644
index 0000000..51de8889
--- /dev/null
+++ b/ios/web/ios_web_shell.gyp
@@ -0,0 +1,66 @@
+# Copyright 2014 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+{
+ 'variables': {
+ 'chromium_code': 1,
+ },
+ 'targets': [
+ {
+ 'target_name': 'ios_web_shell',
+ 'type': 'executable',
+ 'mac_bundle': 1,
+ 'include_dirs': [
+ '../..',
+ ],
+ 'dependencies': [
+ 'ios_web.gyp:ios_web',
+ 'ios_web.gyp:ios_web_app',
+ '../../base/base.gyp:base',
+ '../../net/net.gyp:net',
+ '../../ui/base/ui_base.gyp:ui_base',
+ ],
+ 'xcode_settings': {
+ 'INFOPLIST_FILE': 'shell/Info.plist',
+ 'OTHER_LDFLAGS': [
+ '-Xlinker -objc_abi_version -Xlinker 2'
+ ]
+ },
+ 'sources': [
+ 'shell/app_delegate.h',
+ 'shell/app_delegate.mm',
+ 'shell/shell_browser_state.h',
+ 'shell/shell_browser_state.mm',
+ 'shell/shell_main_delegate.h',
+ 'shell/shell_main_delegate.mm',
+ 'shell/shell_network_delegate.cc',
+ 'shell/shell_network_delegate.h',
+ 'shell/shell_url_request_context_getter.cc',
+ 'shell/shell_url_request_context_getter.h',
+ 'shell/shell_web_client.h',
+ 'shell/shell_web_client.mm',
+ 'shell/shell_web_main_parts.h',
+ 'shell/shell_web_main_parts.mm',
+ 'shell/view_controller.h',
+ 'shell/view_controller.mm',
+ 'shell/web_exe_main.mm',
+ ],
+ 'mac_bundle_resources': [
+ 'shell/Default.png',
+ 'shell/MainView.xib',
+ 'shell/textfield_background@2x.png',
+ 'shell/toolbar_back@2x.png',
+ 'shell/toolbar_forward@2x.png',
+ ],
+ 'link_settings': {
+ 'libraries': [
+ '$(SDKROOT)/System/Library/Frameworks/CoreGraphics.framework',
+ '$(SDKROOT)/System/Library/Frameworks/CoreFoundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/Foundation.framework',
+ '$(SDKROOT)/System/Library/Frameworks/UIKit.framework',
+ ],
+ },
+ },
+ ],
+}
diff --git a/ios/web/public/app/web_main.h b/ios/web/public/app/web_main.h
new file mode 100644
index 0000000..b5d651c
--- /dev/null
+++ b/ios/web/public/app/web_main.h
@@ -0,0 +1,39 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_APP_WEB_MAIN_H_
+#define IOS_WEB_PUBLIC_APP_WEB_MAIN_H_
+
+#include "base/memory/scoped_ptr.h"
+#include "ios/web/public/app/web_main_delegate.h"
+
+namespace web {
+class WebMainRunner;
+
+// Contains parameters passed to WebMain.
+struct WebMainParams {
+ explicit WebMainParams(WebMainDelegate* delegate) : delegate(delegate) {}
+
+ WebMainDelegate* delegate;
+};
+
+// Encapsulates any setup and initialization that is needed by common
+// web/ code. A single instance of this object should be created during app
+// startup (or shortly after launch), and clients must ensure that this object
+// is not destroyed while web/ code is still on the stack.
+//
+// Clients can add custom code to the startup flow by implementing the methods
+// in WebMainDelegate and WebMainParts.
+class WebMain {
+ public:
+ explicit WebMain(const WebMainParams& params);
+ ~WebMain();
+
+ private:
+ scoped_ptr<WebMainRunner> web_main_runner_;
+};
+
+} // namespace web
+
+#endif // IOS_WEB_PUBLIC_APP_WEB_MAIN_H_
diff --git a/ios/web/public/app/web_main_delegate.h b/ios/web/public/app/web_main_delegate.h
new file mode 100644
index 0000000..f462384c
--- /dev/null
+++ b/ios/web/public/app/web_main_delegate.h
@@ -0,0 +1,30 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_APP_WEB_MAIN_DELEGATE_H_
+#define IOS_WEB_PUBLIC_APP_WEB_MAIN_DELEGATE_H_
+
+namespace web {
+
+// Contains delegate hooks that allow a web/ embedder to customize the basic
+// startup and shutdown flow. This delegate is called very early in startup and
+// very late in shutdown, so only minimal code should be run in its
+// implementation. WebMainParts will be a more appropriate place for most
+// startup code.
+class WebMainDelegate {
+ public:
+ virtual ~WebMainDelegate() {}
+
+ // Tells the embedder that the absolute basic startup has been done, i.e.
+ // it's now safe to create singletons and check the command line.
+ virtual void BasicStartupComplete() {}
+
+ // Called right before the process exits.
+ // TODO(rohitrao): This may not be used for anything. Remove if useless.
+ virtual void ProcessExiting() {}
+};
+
+} // namespace web
+
+#endif // IOS_WEB_PUBLIC_APP_WEB_MAIN_DELEGATE_H_
diff --git a/ios/web/public/app/web_main_parts.h b/ios/web/public/app/web_main_parts.h
new file mode 100644
index 0000000..166e9b3
--- /dev/null
+++ b/ios/web/public/app/web_main_parts.h
@@ -0,0 +1,78 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_APP_WEB_MAIN_PARTS_H_
+#define IOS_WEB_PUBLIC_APP_WEB_MAIN_PARTS_H_
+
+#include "base/basictypes.h"
+
+namespace web {
+
+// This class contains different "stages" to be executed by |WebMain()|.
+// Each stage is represented by a single WebMainParts method, called from
+// the corresponding method in |WebMainLoop| (e.g., EarlyInitialization())
+// which does the following:
+// - calls a method (e.g., "PreEarlyInitialization()") which implements
+// platform / tookit specific code for that stage.
+// - calls various methods for things common to all platforms (for that stage).
+// - calls a method (e.g., "PostEarlyInitialization()") for platform-specific
+// code to be called after the common code.
+//
+// Stages:
+// - EarlyInitialization: things which should be done as soon as possible on
+// program start (such as setting up signal handlers) and things to be done
+// at some generic time before the start of the main message loop.
+// - MainMessageLoopStart: things beginning with the start of the main message
+// loop and ending with initialization of the main thread; things which
+// should be done immediately before the start of the main message loop
+// should go in |PreMainMessageLoopStart()|.
+// - RunMainMessageLoopParts: things to be done before and after invoking the
+// main message loop run method (e.g. MessageLoopForUI::current()->Run()).
+//
+// How to add stuff (to existing parts):
+// - Figure out when your new code should be executed. What must happen
+// before/after your code is executed? Are there performance reasons for
+// running your code at a particular time? Document these things!
+// - Unless your new code is just one or two lines, put it into a separate
+// method with a well-defined purpose. (Likewise, if you're adding to an
+// existing chunk which makes it longer than one or two lines, please move
+// the code out into a separate method.)
+//
+class WebMainParts {
+ public:
+ WebMainParts() {}
+ virtual ~WebMainParts() {}
+
+ virtual void PreEarlyInitialization() {}
+
+ virtual void PostEarlyInitialization() {}
+
+ virtual void PreMainMessageLoopStart() {}
+
+ virtual void PostMainMessageLoopStart() {}
+
+ // Called just before any child threads owned by the web
+ // framework are created.
+ //
+ // The main message loop has been started at this point (but has not
+ // been run), and the toolkit has been initialized. Returns the error code
+ // (or 0 if no error).
+ virtual int PreCreateThreads();
+
+ // This is called just before the main message loop is run. The
+ // various browser threads have all been created at this point
+ virtual void PreMainMessageLoopRun() {}
+
+ // This happens after the main message loop has stopped, but before
+ // threads are stopped.
+ virtual void PostMainMessageLoopRun() {}
+
+ // Called as the very last part of shutdown, after threads have been
+ // stopped and destroyed.
+ virtual void PostDestroyThreads() {}
+};
+
+} // namespace web
+
+#endif // IOS_WEB_PUBLIC_APP_WEB_MAIN_PARTS_H_
diff --git a/ios/web/public/app/web_main_parts.mm b/ios/web/public/app/web_main_parts.mm
new file mode 100644
index 0000000..541cc36
--- /dev/null
+++ b/ios/web/public/app/web_main_parts.mm
@@ -0,0 +1,13 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/public/app/web_main_parts.h"
+
+namespace web {
+
+int WebMainParts::PreCreateThreads() {
+ return 0;
+}
+
+} // namespace web
diff --git a/ios/web/shell/Info.plist b/ios/web/shell/Info.plist
new file mode 100644
index 0000000..5740b88
--- /dev/null
+++ b/ios/web/shell/Info.plist
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key>
+ <string>en</string>
+ <key>CFBundleDisplayName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.chromium.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1.0</string>
+ <key>LSRequiresIPhoneOS</key>
+ <true/>
+ <key>UIRequiredDeviceCapabilities</key>
+ <array>
+ <string>armv7</string>
+ </array>
+ <key>UILaunchImages</key>
+ <array>
+ <dict>
+ <key>UILaunchImageMinimumOSVersion</key>
+ <string>7.0</string>
+ <key>UILaunchImageName</key>
+ <string>Default</string>
+ <key>UILaunchImageOrientation</key>
+ <string>Portrait</string>
+ <key>UILaunchImageSize</key>
+ <string>{320, 480}</string>
+ </dict>
+ <dict>
+ <key>UILaunchImageMinimumOSVersion</key>
+ <string>7.0</string>
+ <key>UILaunchImageName</key>
+ <string>Default</string>
+ <key>UILaunchImageOrientation</key>
+ <string>Portrait</string>
+ <key>UILaunchImageSize</key>
+ <string>{320, 568}</string>
+ </dict>
+ <dict>
+ <key>UILaunchImageMinimumOSVersion</key>
+ <string>8.0</string>
+ <key>UILaunchImageName</key>
+ <string>Default</string>
+ <key>UILaunchImageOrientation</key>
+ <string>Portrait</string>
+ <key>UILaunchImageSize</key>
+ <string>{375, 667}</string>
+ </dict>
+ <dict>
+ <key>UILaunchImageMinimumOSVersion</key>
+ <string>8.0</string>
+ <key>UILaunchImageName</key>
+ <string>Default</string>
+ <key>UILaunchImageOrientation</key>
+ <string>Portrait</string>
+ <key>UILaunchImageSize</key>
+ <string>{414, 736}</string>
+ </dict>
+ <dict>
+ <key>UILaunchImageMinimumOSVersion</key>
+ <string>8.0</string>
+ <key>UILaunchImageName</key>
+ <string>Default</string>
+ <key>UILaunchImageOrientation</key>
+ <string>Landscape</string>
+ <key>UILaunchImageSize</key>
+ <string>{414, 736}</string>
+ </dict>
+ </array>
+ <key>UILaunchImages~ipad</key>
+ <array>
+ <dict>
+ <key>UILaunchImageMinimumOSVersion</key>
+ <string>7.0</string>
+ <key>UILaunchImageName</key>
+ <string>Default</string>
+ <key>UILaunchImageOrientation</key>
+ <string>Portrait</string>
+ <key>UILaunchImageSize</key>
+ <string>{768, 1024}</string>
+ </dict>
+ <dict>
+ <key>UILaunchImageMinimumOSVersion</key>
+ <string>7.0</string>
+ <key>UILaunchImageName</key>
+ <string>Default</string>
+ <key>UILaunchImageOrientation</key>
+ <string>Landscape</string>
+ <key>UILaunchImageSize</key>
+ <string>{768, 1024}</string>
+ </dict>
+ </array>
+ <key>UISupportedInterfaceOrientations</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+ <key>UISupportedInterfaceOrientations~ipad</key>
+ <array>
+ <string>UIInterfaceOrientationPortrait</string>
+ <string>UIInterfaceOrientationPortraitUpsideDown</string>
+ <string>UIInterfaceOrientationLandscapeLeft</string>
+ <string>UIInterfaceOrientationLandscapeRight</string>
+ </array>
+</dict>
+</plist>
diff --git a/ios/web/shell/MainView.xib b/ios/web/shell/MainView.xib
new file mode 100644
index 0000000..00cea73
--- /dev/null
+++ b/ios/web/shell/MainView.xib
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="5053" systemVersion="13D65" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
+ <dependencies>
+ <deployment version="1552" identifier="iOS"/>
+ <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="3733"/>
+ </dependencies>
+ <objects>
+ <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="ViewController">
+ <connections>
+ <outlet property="containerView" destination="HS4-2y-YS7" id="KRU-Lk-zhW"/>
+ <outlet property="toolbarView" destination="Mtt-2S-TM5" id="Ngt-zy-T1l"/>
+ <outlet property="view" destination="iN0-l3-epB" id="0A6-5l-qvv"/>
+ </connections>
+ </placeholder>
+ <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+ <view contentMode="scaleToFill" id="iN0-l3-epB">
+ <rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <subviews>
+ <toolbar opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="Mtt-2S-TM5">
+ <rect key="frame" x="0.0" y="20" width="320" height="44"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxY="YES"/>
+ <inset key="insetFor6xAndEarlier" minX="0.0" minY="20" maxX="0.0" maxY="-20"/>
+ <items/>
+ <color key="barTintColor" red="0.33725490196078434" green="0.46666666666666667" blue="0.9882352941176471" alpha="1" colorSpace="calibratedRGB"/>
+ <connections>
+ <outlet property="delegate" destination="-1" id="80Y-wy-gHw"/>
+ </connections>
+ </toolbar>
+ <view contentMode="scaleToFill" id="HS4-2y-YS7">
+ <rect key="frame" x="0.0" y="64" width="320" height="504"/>
+ <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+ <color key="backgroundColor" white="0.66666666666666663" alpha="1" colorSpace="calibratedWhite"/>
+ <inset key="insetFor6xAndEarlier" minX="0.0" minY="20" maxX="0.0" maxY="0.0"/>
+ </view>
+ </subviews>
+ <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
+ <simulatedStatusBarMetrics key="simulatedStatusBarMetrics"/>
+ <simulatedScreenMetrics key="simulatedDestinationMetrics" type="retina4"/>
+ <inset key="insetFor6xAndEarlier" minX="0.0" minY="0.0" maxX="0.0" maxY="-20"/>
+ </view>
+ </objects>
+</document>
diff --git a/ios/web/shell/app_delegate.h b/ios/web/shell/app_delegate.h
new file mode 100644
index 0000000..fba25e8
--- /dev/null
+++ b/ios/web/shell/app_delegate.h
@@ -0,0 +1,16 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_SHELL_APP_DELEGATE_H_
+#define IOS_WEB_SHELL_APP_DELEGATE_H_
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder<UIApplicationDelegate>
+
+@property(nonatomic, retain) UIWindow* window;
+
+@end
+
+#endif // IOS_WEB_SHELL_APP_DELEGATE_H_
diff --git a/ios/web/shell/app_delegate.mm b/ios/web/shell/app_delegate.mm
new file mode 100644
index 0000000..0bba03c
--- /dev/null
+++ b/ios/web/shell/app_delegate.mm
@@ -0,0 +1,64 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/shell/app_delegate.h"
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#include "ios/web/public/app/web_main.h"
+#include "ios/web/public/web_client.h"
+#include "ios/web/public/web_state/web_state.h"
+#include "ios/web/shell/shell_browser_state.h"
+#include "ios/web/shell/shell_main_delegate.h"
+#include "ios/web/shell/shell_web_client.h"
+#import "ios/web/shell/view_controller.h"
+
+@interface AppDelegate () {
+ scoped_ptr<web::ShellMainDelegate> _delegate;
+ scoped_ptr<web::WebMain> _webMain;
+}
+@end
+
+@implementation AppDelegate
+
+@synthesize window = _window;
+
+- (BOOL)application:(UIApplication*)application
+ didFinishLaunchingWithOptions:(NSDictionary*)launchOptions {
+ _window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
+ self.window.backgroundColor = [UIColor whiteColor];
+
+ _delegate.reset(new web::ShellMainDelegate());
+ web::WebMainParams params(_delegate.get());
+ _webMain.reset(new web::WebMain(params));
+
+ web::ShellWebClient* client =
+ static_cast<web::ShellWebClient*>(web::GetWebClient());
+ web::BrowserState* browserState = client->browser_state();
+
+ base::scoped_nsobject<ViewController> controller(
+ [[ViewController alloc] initWithBrowserState:browserState]);
+ self.window.rootViewController = controller;
+ [self.window makeKeyAndVisible];
+ return YES;
+}
+
+- (void)applicationWillResignActive:(UIApplication*)application {
+}
+
+- (void)applicationDidEnterBackground:(UIApplication*)application {
+}
+
+- (void)applicationWillEnterForeground:(UIApplication*)application {
+}
+
+- (void)applicationDidBecomeActive:(UIApplication*)application {
+}
+
+- (void)applicationWillTerminate:(UIApplication*)application {
+ _webMain.reset();
+ _delegate.reset();
+}
+
+@end
diff --git a/ios/web/shell/shell_browser_state.h b/ios/web/shell/shell_browser_state.h
new file mode 100644
index 0000000..f08121d
--- /dev/null
+++ b/ios/web/shell/shell_browser_state.h
@@ -0,0 +1,41 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_SHELL_SHELL_BROWSER_STATE_H_
+#define IOS_WEB_SHELL_SHELL_BROWSER_STATE_H_
+
+#include "ios/web/public/browser_state.h"
+
+#include "base/files/file_path.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/scoped_ptr.h"
+
+namespace web {
+
+class ShellBrowserContext;
+class ShellURLRequestContextGetter;
+
+// Shell-specific implementation of BrowserState. Can only be called from the
+// UI thread.
+class ShellBrowserState : public BrowserState {
+ public:
+ ShellBrowserState();
+ ~ShellBrowserState() override;
+
+ // BrowserState implementation.
+ bool IsOffTheRecord() const override;
+ base::FilePath GetStatePath() const override;
+ net::URLRequestContextGetter* GetRequestContext() override;
+
+ private:
+ base::FilePath path_;
+ scoped_refptr<ShellURLRequestContextGetter> request_context_getter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellBrowserState);
+};
+
+} // namespace web
+
+#endif // IOS_WEB_SHELL_SHELL_BROWSER_STATE_H_
diff --git a/ios/web/shell/shell_browser_state.mm b/ios/web/shell/shell_browser_state.mm
new file mode 100644
index 0000000..4702b1b
--- /dev/null
+++ b/ios/web/shell/shell_browser_state.mm
@@ -0,0 +1,43 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/shell/shell_browser_state.h"
+
+#include "base/base_paths.h"
+#include "base/files/file_path.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/message_loop/message_loop.h"
+#include "base/path_service.h"
+#include "base/threading/thread_restrictions.h"
+#include "ios/web/public/web_thread.h"
+#include "ios/web/shell/shell_url_request_context_getter.h"
+
+namespace web {
+
+ShellBrowserState::ShellBrowserState() : BrowserState() {
+ CHECK(PathService::Get(base::DIR_APP_DATA, &path_));
+
+ request_context_getter_ = new ShellURLRequestContextGetter(
+ GetStatePath(),
+ web::WebThread::GetMessageLoopProxyForThread(web::WebThread::IO),
+ web::WebThread::GetMessageLoopProxyForThread(web::WebThread::FILE),
+ web::WebThread::GetMessageLoopProxyForThread(web::WebThread::CACHE));
+}
+
+ShellBrowserState::~ShellBrowserState() {
+}
+
+bool ShellBrowserState::IsOffTheRecord() const {
+ return false;
+}
+
+base::FilePath ShellBrowserState::GetStatePath() const {
+ return path_;
+}
+
+net::URLRequestContextGetter* ShellBrowserState::GetRequestContext() {
+ return request_context_getter_.get();
+}
+
+} // namespace web
diff --git a/ios/web/shell/shell_main_delegate.h b/ios/web/shell/shell_main_delegate.h
new file mode 100644
index 0000000..1bfd9bd
--- /dev/null
+++ b/ios/web/shell/shell_main_delegate.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_SHELL_SHELL_MAIN_DELEGATE_H_
+#define IOS_WEB_SHELL_SHELL_MAIN_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ios/web/public/app/web_main_delegate.h"
+
+namespace web {
+class ShellWebClient;
+
+class ShellMainDelegate : public WebMainDelegate {
+ public:
+ ShellMainDelegate();
+ ~ShellMainDelegate() override;
+
+ void BasicStartupComplete() override;
+
+ private:
+ scoped_ptr<ShellWebClient> web_client_;
+};
+
+} // namespace web
+
+#endif // IOS_WEB_SHELL_SHELL_MAIN_DELEGATE_H_
diff --git a/ios/web/shell/shell_main_delegate.mm b/ios/web/shell/shell_main_delegate.mm
new file mode 100644
index 0000000..97db23d
--- /dev/null
+++ b/ios/web/shell/shell_main_delegate.mm
@@ -0,0 +1,22 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/shell/shell_main_delegate.h"
+
+#include "ios/web/shell/shell_web_client.h"
+
+namespace web {
+
+ShellMainDelegate::ShellMainDelegate() {
+}
+
+ShellMainDelegate::~ShellMainDelegate() {
+}
+
+void ShellMainDelegate::BasicStartupComplete() {
+ web_client_.reset(new ShellWebClient());
+ web::SetWebClient(web_client_.get());
+}
+
+} // namespace web
diff --git a/ios/web/shell/shell_network_delegate.cc b/ios/web/shell/shell_network_delegate.cc
new file mode 100644
index 0000000..a973f4c
--- /dev/null
+++ b/ios/web/shell/shell_network_delegate.cc
@@ -0,0 +1,95 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/shell/shell_network_delegate.h"
+
+#include "net/base/net_errors.h"
+
+namespace web {
+
+ShellNetworkDelegate::ShellNetworkDelegate() {
+}
+
+ShellNetworkDelegate::~ShellNetworkDelegate() {
+}
+
+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,
+ GURL* allowed_unsafe_redirect_url) {
+ 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 base::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) {
+ return true;
+}
+
+bool ShellNetworkDelegate::OnCanSetCookie(const net::URLRequest& request,
+ const std::string& cookie_line,
+ net::CookieOptions* options) {
+ return true;
+}
+
+bool ShellNetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
+ const base::FilePath& path) const {
+ return true;
+}
+
+bool ShellNetworkDelegate::OnCanThrottleRequest(
+ const net::URLRequest& request) const {
+ return false;
+}
+
+} // namespace web
diff --git a/ios/web/shell/shell_network_delegate.h b/ios/web/shell/shell_network_delegate.h
new file mode 100644
index 0000000..70f0f21
--- /dev/null
+++ b/ios/web/shell/shell_network_delegate.h
@@ -0,0 +1,61 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_SHELL_SHELL_NETWORK_DELEGATE_H_
+#define IOS_WEB_SHELL_SHELL_NETWORK_DELEGATE_H_
+
+#include "base/basictypes.h"
+#include "base/compiler_specific.h"
+#include "net/base/network_delegate_impl.h"
+
+namespace web {
+
+class ShellNetworkDelegate : public net::NetworkDelegateImpl {
+ public:
+ ShellNetworkDelegate();
+ ~ShellNetworkDelegate() override;
+
+ private:
+ // net::NetworkDelegate implementation.
+ int OnBeforeURLRequest(net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ GURL* new_url) override;
+ int OnBeforeSendHeaders(net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ net::HttpRequestHeaders* headers) override;
+ void OnSendHeaders(net::URLRequest* request,
+ const net::HttpRequestHeaders& headers) override;
+ int OnHeadersReceived(
+ net::URLRequest* request,
+ const net::CompletionCallback& callback,
+ const net::HttpResponseHeaders* original_response_headers,
+ scoped_refptr<net::HttpResponseHeaders>* override_response_headers,
+ GURL* allowed_unsafe_redirect_url) override;
+ void OnBeforeRedirect(net::URLRequest* request,
+ const GURL& new_location) override;
+ void OnResponseStarted(net::URLRequest* request) override;
+ void OnRawBytesRead(const net::URLRequest& request, int bytes_read) override;
+ void OnCompleted(net::URLRequest* request, bool started) override;
+ void OnURLRequestDestroyed(net::URLRequest* request) override;
+ void OnPACScriptError(int line_number, const base::string16& error) override;
+ AuthRequiredResponse OnAuthRequired(
+ net::URLRequest* request,
+ const net::AuthChallengeInfo& auth_info,
+ const AuthCallback& callback,
+ net::AuthCredentials* credentials) override;
+ bool OnCanGetCookies(const net::URLRequest& request,
+ const net::CookieList& cookie_list) override;
+ bool OnCanSetCookie(const net::URLRequest& request,
+ const std::string& cookie_line,
+ net::CookieOptions* options) override;
+ bool OnCanAccessFile(const net::URLRequest& request,
+ const base::FilePath& path) const override;
+ bool OnCanThrottleRequest(const net::URLRequest& request) const override;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate);
+};
+
+} // namespace web
+
+#endif // IOS_WEB_SHELL_SHELL_NETWORK_DELEGATE_H_
diff --git a/ios/web/shell/shell_url_request_context_getter.cc b/ios/web/shell/shell_url_request_context_getter.cc
new file mode 100644
index 0000000..b091466
--- /dev/null
+++ b/ios/web/shell/shell_url_request_context_getter.cc
@@ -0,0 +1,159 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/shell/shell_url_request_context_getter.h"
+
+#include "base/base_paths.h"
+#include "base/logging.h"
+#include "base/memory/ref_counted.h"
+#include "base/path_service.h"
+#include "base/threading/worker_pool.h"
+#include "ios/net/cookies/cookie_store_ios.h"
+#include "ios/web/public/web_client.h"
+#include "ios/web/public/web_thread.h"
+#include "ios/web/shell/shell_network_delegate.h"
+#include "net/base/cache_type.h"
+#include "net/cert/cert_verifier.h"
+#include "net/dns/host_resolver.h"
+#include "net/extras/sqlite/sqlite_persistent_cookie_store.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_persister.h"
+#include "net/http/transport_security_state.h"
+#include "net/proxy/proxy_config_service_ios.h"
+#include "net/proxy/proxy_service.h"
+#include "net/ssl/channel_id_service.h"
+#include "net/ssl/default_channel_id_store.h"
+#include "net/ssl/ssl_config_service_defaults.h"
+#include "net/url_request/data_protocol_handler.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 web {
+
+ShellURLRequestContextGetter::ShellURLRequestContextGetter(
+ const base::FilePath& base_path,
+ const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner,
+ const scoped_refptr<base::MessageLoopProxy>& cache_task_runner)
+ : base_path_(base_path),
+ file_task_runner_(file_task_runner),
+ network_task_runner_(network_task_runner),
+ cache_task_runner_(cache_task_runner),
+ proxy_config_service_(new net::ProxyConfigServiceIOS),
+ net_log_(new net::NetLog()) {
+}
+
+ShellURLRequestContextGetter::~ShellURLRequestContextGetter() {
+}
+
+net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() {
+ DCHECK(network_task_runner_->BelongsToCurrentThread());
+
+ if (!url_request_context_) {
+ url_request_context_.reset(new net::URLRequestContext());
+ url_request_context_->set_net_log(net_log_.get());
+ DCHECK(!network_delegate_.get());
+ network_delegate_.reset(new ShellNetworkDelegate);
+ url_request_context_->set_network_delegate(network_delegate_.get());
+
+ storage_.reset(
+ new net::URLRequestContextStorage(url_request_context_.get()));
+
+ // Setup the cookie store.
+ base::FilePath cookie_path;
+ bool cookie_path_found = PathService::Get(base::DIR_APP_DATA, &cookie_path);
+ DCHECK(cookie_path_found);
+ cookie_path = cookie_path.Append("WebShell").Append("Cookies");
+ scoped_refptr<net::CookieMonster::PersistentCookieStore> persistent_store =
+ new net::SQLitePersistentCookieStore(
+ cookie_path, network_task_runner_,
+ web::WebThread::GetBlockingPool()->GetSequencedTaskRunner(
+ web::WebThread::GetBlockingPool()->GetSequenceToken()),
+ true, nullptr);
+ scoped_refptr<net::CookieStoreIOS> cookie_store =
+ new net::CookieStoreIOS(persistent_store.get());
+ storage_->set_cookie_store(cookie_store.get());
+ net::CookieStoreIOS::SwitchSynchronizedStore(nullptr, cookie_store.get());
+
+ std::string user_agent = web::GetWebClient()->GetUserAgent(false);
+ storage_->set_http_user_agent_settings(
+ new net::StaticHttpUserAgentSettings("en-us,en", user_agent));
+ 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_cert_verifier(net::CertVerifier::CreateDefault());
+
+ net::TransportSecurityState* transport_security_state =
+ new net::TransportSecurityState();
+ storage_->set_transport_security_state(transport_security_state);
+ transport_security_persister_.reset(new net::TransportSecurityPersister(
+ transport_security_state, base_path_, file_task_runner_, false));
+ storage_->set_channel_id_service(make_scoped_ptr(
+ new net::ChannelIDService(new net::DefaultChannelIDStore(nullptr),
+ base::WorkerPool::GetTaskRunner(true))));
+ storage_->set_http_server_properties(scoped_ptr<net::HttpServerProperties>(
+ new net::HttpServerPropertiesImpl()));
+
+ scoped_ptr<net::HostResolver> host_resolver(
+ net::HostResolver::CreateDefaultResolver(
+ url_request_context_->net_log()));
+ storage_->set_http_auth_handler_factory(
+ net::HttpAuthHandlerFactory::CreateDefault(host_resolver.get()));
+ storage_->set_host_resolver(host_resolver.Pass());
+
+ 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.channel_id_service =
+ url_request_context_->channel_id_service();
+ network_session_params.net_log = url_request_context_->net_log();
+ 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.host_resolver =
+ url_request_context_->host_resolver();
+
+ base::FilePath cache_path = base_path_.Append(FILE_PATH_LITERAL("Cache"));
+ net::HttpCache::DefaultBackend* main_backend =
+ new net::HttpCache::DefaultBackend(net::DISK_CACHE,
+ net::CACHE_BACKEND_DEFAULT,
+ cache_path, 0, cache_task_runner_);
+
+ 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());
+ bool set_protocol =
+ job_factory->SetProtocolHandler("data", new net::DataProtocolHandler);
+ DCHECK(set_protocol);
+
+ storage_->set_job_factory(job_factory.release());
+ }
+
+ return url_request_context_.get();
+}
+
+scoped_refptr<base::SingleThreadTaskRunner>
+ShellURLRequestContextGetter::GetNetworkTaskRunner() const {
+ return network_task_runner_;
+}
+
+} // namespace web
diff --git a/ios/web/shell/shell_url_request_context_getter.h b/ios/web/shell/shell_url_request_context_getter.h
new file mode 100644
index 0000000..2fdb971
--- /dev/null
+++ b/ios/web/shell/shell_url_request_context_getter.h
@@ -0,0 +1,62 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_SHELL_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
+#define IOS_WEB_SHELL_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 "base/message_loop/message_loop_proxy.h"
+#include "base/single_thread_task_runner.h"
+#include "net/url_request/url_request_context_getter.h"
+
+namespace net {
+class HostResolver;
+class MappedHostResolver;
+class NetworkDelegate;
+class NetLog;
+class ProxyConfigService;
+class TransportSecurityPersister;
+class URLRequestContext;
+class URLRequestContextStorage;
+}
+
+namespace web {
+
+class ShellURLRequestContextGetter : public net::URLRequestContextGetter {
+ public:
+ ShellURLRequestContextGetter(
+ const base::FilePath& base_path,
+ const scoped_refptr<base::SingleThreadTaskRunner>& network_task_runner,
+ const scoped_refptr<base::SingleThreadTaskRunner>& file_task_runner,
+ const scoped_refptr<base::MessageLoopProxy>& cache_task_runner);
+
+ // net::URLRequestContextGetter implementation.
+ net::URLRequestContext* GetURLRequestContext() override;
+ scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
+ const override;
+
+ protected:
+ ~ShellURLRequestContextGetter() override;
+
+ private:
+ base::FilePath base_path_;
+ scoped_refptr<base::SingleThreadTaskRunner> file_task_runner_;
+ scoped_refptr<base::SingleThreadTaskRunner> network_task_runner_;
+ scoped_refptr<base::MessageLoopProxy> cache_task_runner_;
+ 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_;
+ scoped_ptr<net::NetLog> net_log_;
+ scoped_ptr<net::TransportSecurityPersister> transport_security_persister_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellURLRequestContextGetter);
+};
+
+} // namespace web
+
+#endif // IOS_WEB_SHELL_SHELL_URL_REQUEST_CONTEXT_GETTER_H_
diff --git a/ios/web/shell/shell_web_client.h b/ios/web/shell/shell_web_client.h
new file mode 100644
index 0000000..298a5e4
--- /dev/null
+++ b/ios/web/shell/shell_web_client.h
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_SHELL_SHELL_WEB_CLIENT_H_
+#define IOS_WEB_SHELL_SHELL_WEB_CLIENT_H_
+
+#include "base/compiler_specific.h"
+#include "base/memory/scoped_ptr.h"
+#include "ios/web/public/web_client.h"
+
+namespace web {
+class ShellBrowserState;
+class ShellWebMainParts;
+
+class ShellWebClient : public WebClient {
+ public:
+ ShellWebClient();
+ ~ShellWebClient() override;
+
+ // WebClient implementation.
+ WebMainParts* CreateWebMainParts() override;
+ std::string GetProduct() const override;
+ std::string GetUserAgent(bool desktop_user_agent) const override;
+
+ ShellBrowserState* browser_state() const;
+
+ private:
+ scoped_ptr<ShellWebMainParts> web_main_parts_;
+
+ DISALLOW_COPY_AND_ASSIGN(ShellWebClient);
+};
+
+} // namespace web
+
+#endif // IOS_WEB_SHELL_SHELL_WEB_CLIENT_H_
diff --git a/ios/web/shell/shell_web_client.mm b/ios/web/shell/shell_web_client.mm
new file mode 100644
index 0000000..405aeca8
--- /dev/null
+++ b/ios/web/shell/shell_web_client.mm
@@ -0,0 +1,36 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/shell/shell_web_client.h"
+
+#include "ios/web/public/user_agent.h"
+#include "ios/web/shell/shell_web_main_parts.h"
+
+namespace web {
+
+ShellWebClient::ShellWebClient() {
+}
+
+ShellWebClient::~ShellWebClient() {
+}
+
+WebMainParts* ShellWebClient::CreateWebMainParts() {
+ web_main_parts_.reset(new ShellWebMainParts);
+ return web_main_parts_.get();
+}
+
+ShellBrowserState* ShellWebClient::browser_state() const {
+ return web_main_parts_->browser_state();
+}
+
+std::string ShellWebClient::GetProduct() const {
+ return "CriOS/36.77.34.45";
+}
+
+std::string ShellWebClient::GetUserAgent(bool desktop_user_agent) const {
+ std::string product = GetProduct();
+ return web::BuildUserAgentFromProduct(product);
+}
+
+} // namespace web
diff --git a/ios/web/shell/shell_web_main_parts.h b/ios/web/shell/shell_web_main_parts.h
new file mode 100644
index 0000000..6b6f001
--- /dev/null
+++ b/ios/web/shell/shell_web_main_parts.h
@@ -0,0 +1,32 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_SHELL_SHELL_WEB_MAIN_PARTS_H_
+#define IOS_WEB_SHELL_SHELL_WEB_MAIN_PARTS_H_
+
+#include "ios/web/public/app/web_main_parts.h"
+
+#include "base/memory/scoped_ptr.h"
+
+namespace web {
+class ShellBrowserState;
+
+// Shell-specific implementation of WebMainParts.
+class ShellWebMainParts : public WebMainParts {
+ public:
+ ShellWebMainParts();
+ ~ShellWebMainParts() override;
+
+ ShellBrowserState* browser_state() const { return browser_state_.get(); }
+
+ // WebMainParts implementation.
+ void PreMainMessageLoopRun() override;
+
+ private:
+ scoped_ptr<ShellBrowserState> browser_state_;
+};
+
+} // namespace web
+
+#endif // IOS_WEB_SHELL_SHELL_WEB_MAIN_PARTS_H_
diff --git a/ios/web/shell/shell_web_main_parts.mm b/ios/web/shell/shell_web_main_parts.mm
new file mode 100644
index 0000000..1a1c7ee
--- /dev/null
+++ b/ios/web/shell/shell_web_main_parts.mm
@@ -0,0 +1,21 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/shell/shell_web_main_parts.h"
+
+#include "ios/web/shell/shell_browser_state.h"
+
+namespace web {
+
+ShellWebMainParts::ShellWebMainParts() {
+}
+
+ShellWebMainParts::~ShellWebMainParts() {
+}
+
+void ShellWebMainParts::PreMainMessageLoopRun() {
+ browser_state_.reset(new ShellBrowserState);
+}
+
+} // namespace web
diff --git a/ios/web/shell/view_controller.h b/ios/web/shell/view_controller.h
new file mode 100644
index 0000000..c6e11bb
--- /dev/null
+++ b/ios/web/shell/view_controller.h
@@ -0,0 +1,29 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_SHELL_VIEW_CONTROLLER_H_
+#define IOS_WEB_SHELL_VIEW_CONTROLLER_H_
+
+#import <UIKit/UIKit.h>
+
+#include "ios/web/public/web_state/crw_web_delegate.h"
+
+namespace web {
+class BrowserState;
+}
+
+// Implements the main UI for ios_web_shell, including a toolbar and web view.
+@interface ViewController
+ : UIViewController<CRWWebDelegate, UITextFieldDelegate>
+
+@property(nonatomic, retain) IBOutlet UIView* containerView;
+@property(nonatomic, retain) IBOutlet UIToolbar* toolbarView;
+
+// Initializes a new ViewController from |MainView.xib| using the given
+// |browserState|.
+- (instancetype)initWithBrowserState:(web::BrowserState*)browserState;
+
+@end
+
+#endif // IOS_WEB_SHELL_VIEW_CONTROLLER_H_
diff --git a/ios/web/shell/view_controller.mm b/ios/web/shell/view_controller.mm
new file mode 100644
index 0000000..16e78fe
--- /dev/null
+++ b/ios/web/shell/view_controller.mm
@@ -0,0 +1,334 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/shell/view_controller.h"
+
+#include "base/mac/objc_property_releaser.h"
+#import "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/sys_string_conversions.h"
+#include "ios/net/cookies/cookie_store_ios.h"
+#import "ios/net/crn_http_protocol_handler.h"
+#import "ios/web/navigation/crw_session_controller.h"
+#include "ios/web/navigation/web_load_params.h"
+#import "ios/web/net/crw_url_verifying_protocol_handler.h"
+#include "ios/web/net/request_tracker_factory_impl.h"
+#import "ios/web/net/web_http_protocol_handler_delegate.h"
+#include "ios/web/public/referrer.h"
+#import "ios/web/public/web_controller_factory.h"
+#include "ios/web/public/web_state/web_state.h"
+#include "ios/web/public/web_view_util.h"
+#include "ios/web/shell/shell_browser_state.h"
+#include "ios/web/web_state/ui/crw_web_controller.h"
+#include "ios/web/web_state/web_state_impl.h"
+#include "ui/base/page_transition_types.h"
+
+namespace {
+// Returns true if WKWebView should be used instead of UIWebView.
+// TODO(stuartmorgan): Decide on a better way to control this.
+bool UseWKWebView() {
+#if defined(FORCE_ENABLE_WKWEBVIEW)
+ return web::IsWKWebViewSupported();
+#else
+ return false;
+#endif
+}
+}
+
+@interface ViewController () {
+ web::BrowserState* _browserState;
+ base::scoped_nsobject<CRWWebController> _webController;
+ scoped_ptr<web::RequestTrackerFactoryImpl> _requestTrackerFactory;
+ scoped_ptr<web::WebHTTPProtocolHandlerDelegate> _httpProtocolDelegate;
+
+ base::mac::ObjCPropertyReleaser _propertyReleaser_ViewController;
+}
+@property(nonatomic, readwrite, retain) UITextField* field;
+@end
+
+@implementation ViewController
+
+@synthesize field = _field;
+@synthesize containerView = _containerView;
+@synthesize toolbarView = _toolbarView;
+
+- (instancetype)initWithBrowserState:(web::BrowserState*)browserState {
+ self = [super initWithNibName:@"MainView" bundle:nil];
+ if (self) {
+ _propertyReleaser_ViewController.Init(self, [ViewController class]);
+ _browserState = browserState;
+ }
+ return self;
+}
+
+- (void)dealloc {
+ net::HTTPProtocolHandlerDelegate::SetInstance(nullptr);
+ net::RequestTracker::SetRequestTrackerFactory(nullptr);
+ [super dealloc];
+}
+
+- (void)viewDidLoad {
+ [super viewDidLoad];
+
+ // Set up the toolbar buttons.
+ UIButton* back = [UIButton buttonWithType:UIButtonTypeCustom];
+ [back setImage:[UIImage imageNamed:@"toolbar_back"]
+ forState:UIControlStateNormal];
+ [back setFrame:CGRectMake(0, 0, 44, 44)];
+ [back setImageEdgeInsets:UIEdgeInsetsMake(5, 5, 4, 4)];
+ [back setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
+ [back addTarget:self
+ action:@selector(back)
+ forControlEvents:UIControlEventTouchUpInside];
+
+ UIButton* forward = [UIButton buttonWithType:UIButtonTypeCustom];
+ [forward setImage:[UIImage imageNamed:@"toolbar_forward"]
+ forState:UIControlStateNormal];
+ [forward setFrame:CGRectMake(44, 0, 44, 44)];
+ [forward setImageEdgeInsets:UIEdgeInsetsMake(5, 5, 4, 4)];
+ [forward setAutoresizingMask:UIViewAutoresizingFlexibleRightMargin];
+ [forward addTarget:self
+ action:@selector(forward)
+ forControlEvents:UIControlEventTouchUpInside];
+
+ base::scoped_nsobject<UITextField> field([[UITextField alloc]
+ initWithFrame:CGRectMake(88, 6, CGRectGetWidth([_toolbarView frame]) - 98,
+ 31)]);
+ [field setDelegate:self];
+ [field setBackground:[[UIImage imageNamed:@"textfield_background"]
+ resizableImageWithCapInsets:UIEdgeInsetsMake(
+ 12, 12, 12, 12)]];
+ [field setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
+ [field setKeyboardType:UIKeyboardTypeWebSearch];
+ [field setAutocorrectionType:UITextAutocorrectionTypeNo];
+ [field setClearButtonMode:UITextFieldViewModeWhileEditing];
+ self.field = field;
+
+ [_toolbarView addSubview:back];
+ [_toolbarView addSubview:forward];
+ [_toolbarView addSubview:field];
+
+ // Set up the network stack before creating the WebState.
+ [self setUpNetworkStack];
+
+ scoped_ptr<web::WebStateImpl> webState(new web::WebStateImpl(_browserState));
+ webState->GetNavigationManagerImpl().InitializeSession(nil, nil, NO, 0);
+ web::WebViewType webViewType =
+ UseWKWebView() ? web::WK_WEB_VIEW_TYPE : web::UI_WEB_VIEW_TYPE;
+ _webController.reset(web::CreateWebController(webViewType, webState.Pass()));
+ [_webController setDelegate:self];
+ [_webController setWebUsageEnabled:YES];
+
+ [[_webController view] setFrame:[_containerView bounds]];
+ [_containerView addSubview:[_webController view]];
+
+ web::WebLoadParams params(GURL("https://dev.chromium.org/"));
+ params.transition_type = ui::PAGE_TRANSITION_TYPED;
+ [_webController loadWithParams:params];
+}
+
+- (void)setUpNetworkStack {
+ // Disable the default cache.
+ [NSURLCache setSharedURLCache:nil];
+
+ _httpProtocolDelegate.reset(new web::WebHTTPProtocolHandlerDelegate(
+ _browserState->GetRequestContext()));
+ net::HTTPProtocolHandlerDelegate::SetInstance(_httpProtocolDelegate.get());
+ BOOL success = [NSURLProtocol registerClass:[CRNHTTPProtocolHandler class]];
+ DCHECK(success);
+ // The CRWURLVerifyingProtocolHandler is used to verify URL in the
+ // CRWWebController. It must be registered after the HttpProtocolHandler
+ // because handlers are called in the reverse order of declaration.
+ success =
+ [NSURLProtocol registerClass:[CRWURLVerifyingProtocolHandler class]];
+ DCHECK(success);
+ _requestTrackerFactory.reset(
+ new web::RequestTrackerFactoryImpl(std::string()));
+ net::RequestTracker::SetRequestTrackerFactory(_requestTrackerFactory.get());
+ net::CookieStoreIOS::SetCookiePolicy(net::CookieStoreIOS::ALLOW);
+}
+
+- (void)didReceiveMemoryWarning {
+ [super didReceiveMemoryWarning];
+}
+
+- (UIBarPosition)positionForBar:(id<UIBarPositioning>)bar {
+ if (bar == _toolbarView) {
+ return UIBarPositionTopAttached;
+ }
+ return UIBarPositionAny;
+}
+
+- (void)back {
+ if ([_webController canGoBack]) {
+ [_webController goBack];
+ }
+}
+
+- (void)forward {
+ if ([_webController canGoForward]) {
+ [_webController goForward];
+ }
+}
+
+- (BOOL)textFieldShouldReturn:(UITextField*)field {
+ GURL url = GURL(base::SysNSStringToUTF8([field text]));
+
+ // Do not try to load invalid URLs.
+ if (url.is_valid()) {
+ web::WebLoadParams params(url);
+ params.transition_type = ui::PAGE_TRANSITION_TYPED;
+ [_webController loadWithParams:params];
+ }
+
+ [field resignFirstResponder];
+ [self updateToolbar];
+ return YES;
+}
+
+- (void)updateToolbar {
+ // Do not update the URL if the text field is currently being edited.
+ if ([_field isFirstResponder]) {
+ return;
+ }
+
+ const GURL& url = [_webController webStateImpl]->GetVisibleURL();
+ [_field setText:base::SysUTF8ToNSString(url.spec())];
+}
+
+// -----------------------------------------------------------------------
+#pragma mark Bikeshedding Implementation
+
+// Overridden to allow this view controller to receive motion events by being
+// first responder when no other views are.
+- (BOOL)canBecomeFirstResponder {
+ return YES;
+}
+
+- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent*)event {
+ if (event.subtype == UIEventSubtypeMotionShake) {
+ [self updateToolbarColor];
+ }
+}
+
+- (void)updateToolbarColor {
+ // Cycle through the following set of colors:
+ NSArray* colors = @[
+ // Vanilla Blue.
+ [UIColor colorWithRed:0.337 green:0.467 blue:0.988 alpha:1.0],
+ // Vanilla Red.
+ [UIColor colorWithRed:0.898 green:0.110 blue:0.137 alpha:1.0],
+ // Blue Grey.
+ [UIColor colorWithRed:0.376 green:0.490 blue:0.545 alpha:1.0],
+ // Brown.
+ [UIColor colorWithRed:0.475 green:0.333 blue:0.282 alpha:1.0],
+ // Purple.
+ [UIColor colorWithRed:0.612 green:0.153 blue:0.690 alpha:1.0],
+ // Teal.
+ [UIColor colorWithRed:0.000 green:0.737 blue:0.831 alpha:1.0],
+ // Deep Orange.
+ [UIColor colorWithRed:1.000 green:0.341 blue:0.133 alpha:1.0],
+ // Indigo.
+ [UIColor colorWithRed:0.247 green:0.318 blue:0.710 alpha:1.0],
+ // Vanilla Green.
+ [UIColor colorWithRed:0.145 green:0.608 blue:0.141 alpha:1.0],
+ // Pinkerton.
+ [UIColor colorWithRed:0.914 green:0.118 blue:0.388 alpha:1.0],
+ ];
+
+ NSUInteger currentIndex = [colors indexOfObject:_toolbarView.barTintColor];
+ if (currentIndex == NSNotFound) {
+ currentIndex = 0;
+ }
+ NSUInteger newIndex = currentIndex + 1;
+ if (newIndex >= [colors count]) {
+ // TODO(rohitrao): Out of colors! Consider prompting the user to pick their
+ // own color here. Also consider allowing the user to choose the entire set
+ // of colors or allowing the user to choose color randomization.
+ newIndex = 0;
+ }
+ _toolbarView.barTintColor = [colors objectAtIndex:newIndex];
+}
+
+// -----------------------------------------------------------------------
+// WebDelegate implementation.
+
+- (void)webWillAddPendingURL:(const GURL&)url
+ transition:(ui::PageTransition)transition {
+}
+- (void)webDidAddPendingURL {
+ [self updateToolbar];
+}
+- (void)webCancelStartLoadingRequest {
+}
+- (void)webDidStartLoadingURL:(const GURL&)currentUrl
+ shouldUpdateHistory:(BOOL)updateHistory {
+ [self updateToolbar];
+}
+- (void)webDidFinishWithURL:(const GURL&)url loadSuccess:(BOOL)loadSuccess {
+ [self updateToolbar];
+}
+
+- (CRWWebController*)webPageOrderedOpen:(const GURL&)url
+ referrer:(const web::Referrer&)referrer
+ windowName:(NSString*)windowName
+ inBackground:(BOOL)inBackground {
+ return nil;
+}
+
+- (CRWWebController*)webPageOrderedOpenBlankWithReferrer:
+ (const web::Referrer&)referrer
+ inBackground:(BOOL)inBackground {
+ return nil;
+}
+
+- (void)webPageOrderedClose {
+}
+- (void)goDelta:(int)delta {
+}
+- (void)openURLWithParams:(const web::WebState::OpenURLParams&)params {
+}
+- (BOOL)openExternalURL:(const GURL&)url {
+ return NO;
+}
+- (void)presentSSLError:(const net::SSLInfo&)info
+ forSSLStatus:(const web::SSLStatus&)status
+ recoverable:(BOOL)recoverable
+ callback:(SSLErrorCallback)shouldContinue {
+}
+- (void)presentSpoofingError {
+}
+- (void)webLoadCancelled:(const GURL&)url {
+}
+- (void)webDidUpdateHistoryStateWithPageURL:(const GURL&)pageUrl {
+}
+- (void)webController:(CRWWebController*)webController
+ retrievePlaceholderOverlayImage:(void (^)(UIImage*))block {
+}
+- (void)webController:(CRWWebController*)webController
+ onFormResubmissionForRequest:(NSURLRequest*)request
+ continueBlock:(ProceduralBlock)continueBlock
+ cancelBlock:(ProceduralBlock)cancelBlock {
+}
+- (void)webWillReload {
+}
+- (void)webWillInitiateLoadWithParams:(web::WebLoadParams&)params {
+}
+- (void)webDidUpdateSessionForLoadWithParams:(const web::WebLoadParams&)params
+ wasInitialNavigation:(BOOL)initialNavigation {
+}
+- (void)webWillFinishHistoryNavigationFromEntry:(CRWSessionEntry*)fromEntry {
+}
+- (void)webWillGoDelta:(int)delta {
+}
+- (void)webDidPrepareForGoBack {
+}
+- (int)downloadImageAtUrl:(const GURL&)url
+ maxBitmapSize:(uint32_t)maxBitmapSize
+ callback:
+ (const web::WebState::ImageDownloadCallback&)callback {
+ return -1;
+}
+
+@end
diff --git a/ios/web/shell/web_exe_main.mm b/ios/web/shell/web_exe_main.mm
new file mode 100644
index 0000000..0e7c58b
--- /dev/null
+++ b/ios/web/shell/web_exe_main.mm
@@ -0,0 +1,14 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import <UIKit/UIKit.h>
+
+#import "ios/web/shell/app_delegate.h"
+
+int main(int argc, char* argv[]) {
+ @autoreleasepool {
+ return UIApplicationMain(argc, argv, nil,
+ NSStringFromClass([AppDelegate class]));
+ }
+}